英文:
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:
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,
- You know the dimensions of array while compiling
- 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论