or9ob
or9ob

Reputation: 2392

Initialize a 2d dynamic array in Go

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:

Upvotes: 21

Views: 19775

Answers (3)

Jeevan
Jeevan

Reputation: 319

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

Upvotes: 5

Salvador Dali
Salvador Dali

Reputation: 222481

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.

Upvotes: 9

James Henstridge
James Henstridge

Reputation: 43899

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"

Upvotes: 17

Related Questions