Golang多维切片复制

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

Golang multidimensional slice copy

问题

我试图制作一个多维切片的克隆,因为当我在复制的切片中更改元素时,原始切片中的元素也被覆盖了。

唯一对我有效的方法是:

duplicate := make([][]int, len(matrix))
for i := 0; i < len(matrix); i++ {
	duplicate[i] = make([]int, len(matrix[0]))
	for j := 0; j < len(matrix[0]); j++ {
		duplicate[i][j] = matrix[i][j]
	}
}

是否有其他更短或更高效的方法来实现相同的结果?谢谢

英文:

I was trying to make a clone of multidimensional slice, because when I have changed elements in the duplicated slice, the elements in the original one were overwritten also.

The only method that worked for me was:

duplicate := make([][]int, len(matrix))
for i := 0; i &lt; len(matrix); i++ {
	duplicate[i] = make([]int, len(matrix[0]))
	for j := 0; j &lt; len(matrix[0]); j++ {
		duplicate[i][j] = matrix[i][j]
	}
}

is there any other way - shorter or more efficient to achieve the same result? thanks

答案1

得分: 21

你可以在内部循环中使用copy(这样更高效),在外部循环中使用range(这样代码更清晰)。

结果:

duplicate := make([][]int, len(matrix))
for i := range matrix {
    duplicate[i] = make([]int, len(matrix[i]))
    copy(duplicate[i], matrix[i])
}

如果你的目标是效率,可能需要提前进行更多的分配。这样做不会导致代码更易读,但如果你经常这样做,会导致更高效的代码。这段代码假设你至少有一行,并且所有行的长度相同。你需要为此添加测试。

n := len(matrix)
m := len(matrix[0])
duplicate := make([][]int, n)
data := make([]int, n*m)
for i := range matrix {
    start := i*m
    end := start + m
    duplicate[i] = data[start:end:end]
    copy(duplicate[i], matrix[i])
}

根据你的需求,可能有意义创建一个“矩阵类型”,该类型仅使用单个切片实现。切片的切片并不是最高效的数据结构,即使它更简单易用。


在决定是否需要效率之前,请确保你在拷贝操作上花费了大量时间,可以使用性能分析工具进行检查。然后,在确定这确实是一个热点之后,开始运行基准测试。有关详细信息,请参阅https://golang.org/pkg/testing/#hdr-Benchmarks。

英文:

You can use copy for the inner loop (which should be more efficient) and range for the outer loop (which results in nicer code).

Result:

duplicate := make([][]int, len(matrix))
for i := range matrix {
    duplicate[i] = make([]int, len(matrix[i]))
    copy(duplicate[i], matrix[i])
}

If your goal is efficiency, it may make sense to do more allocation up front. This doesn't lead to more readable code but will lead to more efficient code if you are doing this often. This code assumes you have at least one row and that all rows are of the same length. You will need to add tests for that.

n := len(matrix)
m := len(matrix[0])
duplicate := make([][]int, n)
data := make([]int, n*m)
for i := range matrix {
    start := i*m
    end := start + m
    duplicate[i] = data[start:end:end]
    copy(duplicate[i], matrix[i])
}

Depending on what you are doing, it may make sense to make a "matrix type" that is implemented using only a single slice. A slice of slices is not the most efficient data structure, even if it is simpler to work with.


Before deciding if you need to be efficient, make sure that you are spending a lot of time doing copying using profiling. Then, after you have determined this is in fact a hotspot, start running benchmarks. See https://golang.org/pkg/testing/#hdr-Benchmarks for details.

答案2

得分: -1

你可以通过gob来进行往返转换:

package main

import (
   "bytes"
   "encoding/gob"
   "fmt"
)

func sliceCopy(in, out interface{}) {
   buf := new(bytes.Buffer)
   gob.NewEncoder(buf).Encode(in)
   gob.NewDecoder(buf).Decode(out)
}

func main() {
   a := [][]int{
      {1, 2, 3}, {4, 5, 6}, {7, 8, 9},
   }
   var b [][]int
   sliceCopy(a, &b)
   fmt.Println(b)
}

https://golang.org/pkg/encoding/gob

英文:

You could roundtrip it through gob:

package main

import (
   &quot;bytes&quot;
   &quot;encoding/gob&quot;
   &quot;fmt&quot;
)

func sliceCopy(in, out interface{}) {
   buf := new(bytes.Buffer)
   gob.NewEncoder(buf).Encode(in)
   gob.NewDecoder(buf).Decode(out)
}

func main() {
   a := [][]int{
      {1, 2, 3}, {4, 5, 6}, {7, 8, 9},
   }
   var b [][]int
   sliceCopy(a, &amp;b)
   fmt.Println(b)
}

https://golang.org/pkg/encoding/gob

huangapple
  • 本文由 发表于 2017年8月2日 23:44:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/45465368.html
匿名

发表评论

匿名网友

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

确定