Go 中的多维数组

Fre*_*ore 3 arrays go multidimensional-array

我正在学习 Go,我正在尝试生成一个二维数组 [][]int,它在嵌套的 for 循环中只是在该位置放置一个值。我是否总是必须使用 make 创建固定大小的数组,或者是否可以在循环中动态完成此操作?

genMap := [][]int{}
for i := 0; i < 10; i++ {
    for j := 0; j < 10; j++ {
        genMap[i][j] = 1
    }
}
return genMap
Run Code Online (Sandbox Code Playgroud)

但这会导致错误索引超出范围。所以我不太确定这在 Go 中是否可能,或者我错过了一些重要的东西

PaS*_*STE 11

你确实错过了一些关键的东西——在 go 中,切片(从技术上讲,这是你用语句创建的东西genMap := [][]int{})默认长度为零。您无法访问 的任何元素,genMap因为没有可供访问的元素,因此任何尝试这样做都会导致索引超出范围错误。作为参考,请查看之前关于 SO 的答案

有几种方法可以解决这个问题。您可以预先分配切片,在循环迭代时附加到每个切片,或者为数据选择更方便的数据类型。

预分配切片

正如您所提到的,您可以简单地将切片分配到循环之前的已知长度。这可能会提高速度,因为每次必须扩展切片的范围时,您都不会在内存中移动值。但请记住,您的“二维数组”实际上是整数切片的切片,因此每个内部切片(部分[]int)必须在单独的步骤中分配。您可以在循环中执行此操作:

genMap := make([][]int, 10)      // Make the outer slice and give it size 10
for i := 0; i < 10; i ++ {
    genMap[i] = make([]int, 10)  // Make one inner slice per iteration and give it size 10
    for j := 0; j < 10; j++ {
        genMap[i][j] = 1
    }
}
Run Code Online (Sandbox Code Playgroud)

查看正在运行的代码。

迭代时追加

如果您不知道外部或内部切片有多大,这非常有用。如前所述,缺点是当您调用 时,您可能会移动大量内存append,因此这可能效率低下。

genMap := [][]int{}             // Make the outer slice with size 0
for i := 0; i < 10; i ++ {
    m := []int{}                // Make one inner slice per iteration with size 0
    for j := 0; j < 10; j++ {
        m = append(m, 1)        // Append to the inner slice
    }
    genMap = append(genMap, m)  // Append to the outer slice
}
Run Code Online (Sandbox Code Playgroud)

查看正在运行的代码。

选择更方便的数据类型

有时,设计一个满足您的需求但将数据存储在连续切片而不是切片切片中的结构更有用。这可以提高代码的性能和可读性。这样的结构可以定义方法来帮助插入和查找索引,如下所示:

type TwoD struct {
    data  []int
    xSpan int
    ySpan int
}

// Factory function
func NewTwoD(xspan, yspan int) *TwoD {
    return &TwoD{data: make([]int, xspan*yspan), xSpan: xspan, ySpan: yspan}
}

func (td *TwoD) Put(x, y, value int) {
    // optionally do some bounds checking here
    td.data[x*td.ySpan+y] = value
}

func (td *TwoD) Get(x, y int) int {
    // optionally do some bounds checking here
    return td.data[x*td.ySpan+y]
}

func main() {
    genMap := NewTwoD(10, 10)
    for i := 0; i < 10; i++ {
        for j := 0; j < 10; j++ {
            genMap.Put(i, j, 1)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

查看正在运行的代码。

此外,如果您计划使用这些值进行线性代数,请考虑查看Gonum以获得精心设计、经过良好测试的代码来帮助您。