在Go语言中初始化一个二维动态数组可以使用以下代码:

huangapple go评论94阅读模式
英文:

Initialize a 2d dynamic array in Go

问题

我正在尝试在Go语言中创建一个二维数组:

board := make([][]string, m)
for i := range board {
    board[i] = make([]string, n)
}

然而,考虑到这种冗长的写法,我想知道是否有更好或更简洁的方法来处理这个问题(无论是生成动态数组,还是使用不同的/惯用的数据结构来处理这种类似棋盘游戏的数据)?

背景信息:

  • 这是一个棋盘游戏
  • 棋盘的尺寸在用户开始游戏之前是未知的(比如说MxN)
  • 我想在每个单元格中存储一个任意字符(或单个字符的字符串)。在我的井字棋游戏中,这将是'X'或'O'(或者用户选择的任何其他字符)。
英文:

I am trying to create a 2d array in Go:

board := make([][]string, m)
for i := range board {
	board[i] = make([]string, n)
}

However, given the verbosity of that, I am wondering if there is a better or more succinct way to handle this problem (either to generate dynamic arrays, or a different/idiomatic data-structure to handle such board-game like data)?


Background:

  • this is for a board game
  • the dimensions of the board are not known until a user starts playing (so, say, MxN).
  • I want to store an arbitrary character (or a single char string) in each cell. In my TicTacToe game that will be the 'X' or an 'O' (or any other character the user chooses).

答案1

得分: 17

你在示例代码中构建的不是一个二维数组,而是一个切片的切片:每个子切片的长度可以不同,这就是为什么你需要为每个子切片进行单独的分配。

如果你想用单个分配来表示棋盘,一种选择是分配一个单独的切片,然后使用简单的算术运算来确定元素的位置。例如:

board := make([]string, m*n)
board[i*m + j] = "abc" // 类似于 board[i][j] = "abc"
英文:

What you are building in your sample code is not a 2D array, but rather a slice of slices: each of the sub-slices could be of a different length with this type, which is why you have separate allocations for each.

If you want to represent the board with a single allocation though, one option would be to allocate a single slice, and then use simple arithmetic to determine where elements are. For example:

board := make([]string, m*n)
board[i*m + j] = "abc" // like board[i][j] = "abc"

答案2

得分: 8

你描述的方法创建了一个切片的切片,看起来类似于你想要的二维数组。我建议你将类型更改为uint8,因为你只关心三种状态:nothing / first / second player。

这种方法会分别分配每一行(在你的基准测试中,你会看到至少m + 1 allocs/op)。这并不是很好,因为无法保证单独的分配会靠近彼此。

为了保持局部性,你可以这样做:

M := make([][]uint8, row)
e := make([]uint8, row * col)
for i := range M {
    a[i] = e[i * col:(i + 1) * col]
}

这样只会有2次分配,切片的切片将保持数据的局部性。注意,你仍然可以以二维格式访问你的M,比如M[2][6]

这是一个很好的视频,可以更快地解释如何做到这一点。

英文:

The way you described creates a slice of slices, which looks similar to a 2d array that you want. I would suggest you to change the type to uint8, as you only care about 3 states nothing / first / second player.

This allocates each row separately (you will see at least m + 1 allocs/op in your benchmarks). This is not really nice because there is no guarantee that the separate allocations would be localized close to each other.

To maintain locality you can do something like this:

M := make([][]uint8, row)
e := make([]uint8, row * col)
for i := range M {
    a[i] = e[i * col:(i + 1) * col]
}

This will end up with only 2 allocations and the slice of slices will maintain data locality. Note that you will still be able to access your M in 2d format M[2][6].

A good video which explains how to do this even faster.

答案3

得分: 4

对于多维数组,我们可以有以下两种用例:

  1. 在编译时就知道数组的维度。
  2. 只有在运行时才知道数组的维度,例如从用户输入中获取。

对于用例1:

matr := [5][5]int{}

对于用例2:

var m, n int
fmt.Scan(&m, &n)
var mat = make([][]int, m)
for i := range mat {
    mat[i] = make([]int, n)
    fmt.Printf("Row %d: %v\n", i, mat[i])
}

简而言之,我们需要依靠make来创建动态数组。

英文:

For a multi dimensional array, we can have any of the 2 uses cases,

  1. You know the dimensions of array while compiling
  2. You get to know the array dimension only at runtime, ie may from the user
    input or so

For use case 1

matr := [5][5]int{}

For use case 2

var m, n int
fmt.Scan(&m, &n)
var mat = make([][]int, m)
for i := range mat {
	mat[i] = make([]int, n)
	fmt.Printf("Row %d: %v\n", i, mat[i])
}

In short, we have to rely on make for creating dynamic arrays

huangapple
  • 本文由 发表于 2014年5月26日 20:02:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/23869717.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定