意外地,基于`map[int][][]int`的代码结果。

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

Unexpectedly the result for my code based on `map[int][][]int`

问题

我在Linux(Ubuntu 1604)/amd64上使用Go版本1.7.4、1.8和1.8.1运行了我的代码。

我试图使用结构体m := map[int][][]int编写一个以下功能的代码。

对于一个数组numbers := []int{0,1,2,3,4},让m[0] = [][]int{[]int{0}, []int{1}, []int{2}, []int{3}, []int{4}}
然后将numbers中的一个数字n添加到m[i]的所有列表中,然后m[1]如下所示。

m[1] -> [[0,1], [0,2],..,[0,4],[1,2],[1,3],..,[1,4],...,,[2,3],[2,4],[3,4]]

对于m[2] -> [[0,1,2],[0,1,3],.....]m[3]m[4]也是如此。

以下是我的代码。

package main

import (
	"fmt"
)

func main() {
	n := 5
	m := make(map[int][][]int)
	list := make([][]int, 0)
	for i := 0; i < n; i++ {
		list = append(list, []int{i})
	}
	m[0] = list
	fmt.Println(m)
	for level := 1; level < n; level++ {
		newlist := make([][]int, 0)
		for _, lst := range m[level-1] {
			for i := 0; i < n; i++ {
				if i > lst[len(lst)-1] {
					newlst := append(lst, i)
					newlist = append(newlist, newlst)
					fmt.Println(level, ":", lst, i, "->", newlst, "=>", newlist)
				}
			}
		}
		m[level] = newlist
	}
	fmt.Println(m)
}

以下是输出结果。

map[0:[[0] [1] [2] [3] [4]]]
1 : [0] 1 -> [0 1] => [[0 1]]
1 : [0] 2 -> [0 2] => [[0 1] [0 2]]
1 : [0] 3 -> [0 3] => [[0 1] [0 2] [0 3]]
1 : [0] 4 -> [0 4] => [[0 1] [0 2] [0 3] [0 4]]
1 : [1] 2 -> [1 2] => [[0 1] [0 2] [0 3] [0 4] [1 2]]
1 : [1] 3 -> [1 3] => [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3]]
1 : [1] 4 -> [1 4] => [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4]]
1 : [2] 3 -> [2 3] => [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3]]
1 : [2] 4 -> [2 4] => [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4]]
1 : [3] 4 -> [3 4] => [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4] [3 4]]
2 : [0 1] 2 -> [0 1 2] => [[0 1 2]]
2 : [0 1] 3 -> [0 1 3] => [[0 1 2] [0 1 3]]
2 : [0 1] 4 -> [0 1 4] => [[0 1 2] [0 1 3] [0 1 4]]
2 : [0 2] 3 -> [0 2 3] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3]]
2 : [0 2] 4 -> [0 2 4] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4]]
2 : [0 3] 4 -> [0 3 4] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4]]
2 : [1 2] 3 -> [1 2 3] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3]]
2 : [1 2] 4 -> [1 2 4] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4]]
2 : [1 3] 4 -> [1 3 4] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4]]
2 : [2 3] 4 -> [2 3 4] => [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]
3 : [0 1 2] 3 -> [0 1 2 3] => [[0 1 2 3]]
3 : [0 1 2] 4 -> [0 1 2 4] => [[0 1 2 4] [0 1 2 4]]
3 : [0 1 3] 4 -> [0 1 3 4] => [[0 1 2 4] [0 1 2 4] [0 1 3 4]]
3 : [0 2 3] 4 -> [0 2 3 4] => [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4]]
3 : [1 2 3] 4 -> [1 2 3 4] => [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]
map[4:[] 0:[[0] [1] [2] [3] [4]] 1:[[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4] [3 4]] 2:[[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]] 3:[[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]]

问题出在这里。

3 : [0 1 2] 3 -> [0 1 2 3] => [[0 1 2 3]]
3 : [0 1 2] 4 -> [0 1 2 4] => [[0 1 2 4] [0 1 2 4]]           
3 : [0 1 3] 4 -> [0 1 3 4] => [[0 1 2 4] [0 1 2 4] [0 1 3 4]]
3 : [0 2 3] 4 -> [0 2 3 4] => [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4]]
3 : [1 2 3] 4 -> [1 2 3 4] => [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]

正确的输出应该是:

3 : [0 1 2] 3 -> [0 1 2 3] => [[0 1 2 3]]
3 : [0 1 2] 4 -> [0 1 2 4] => [[0 1 2 **3**] [0 1 2 4]]           
3 : [0 1 3] 4 -> [0 1 3 4] => [[0 1 2 **3**] [0 1 2 4] [0 1 3 4]]
3 : [0 2 3] 4 -> [0 2 3 4] => [[0 1 2 **3**] [0 1 2 4] [0 1 3 4] [0 2 3 4]]
3 : [1 2 3] 4 -> [1 2 3 4] => [[0 1 2 **3**] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]

我不知道为什么会出现这个问题,但我认为这可能是Go编译器或运行时的一个错误。

出现问题的原因是什么?如果是Go的错误或者我的代码错误,该如何解决?谢谢!

英文:

I ran my code in Go versions 1.7.4, 1.8, 1.8.1 on Linux(Ubuntu 1604)/amd64

I'm trying to use a structure m := map[int][][]int to write a code to do something below.

For an array numbers := []int{0,1,2,3,4}, let m[0] = [][]int{[]int{0}, []int{1}, []int{2}, []int{3}, []int{4}},
and append a number n within numbers to all list of m[i], then m[1] as below.

m[1] -&gt; [[0,1], [0,2],..,[0,4],[1,2],[1,3],..,[1,4],...,,[2,3],[2,4],[3,4]]

and so on for m[2] -&gt; [[0,1,2],[0,1,3],.....], m[3], m[4]

Here is my code.

package main

import (
	&quot;fmt&quot;
)

func main() {
	n := 5
	m := make(map[int][][]int)
	list := make([][]int, 0)
	for i := 0; i &lt; n; i++ {
		list = append(list, []int{i})
	}
	m[0] = list
	fmt.Println(m)
	for level := 1; level &lt; n; level++ {
		newlist := make([][]int, 0)
		for _, lst := range m[level-1] {
			for i := 0; i &lt; n; i++ {
				if i &gt; lst[len(lst)-1] {
					newlst := append(lst, i)
					newlist = append(newlist, newlst)
					fmt.Println(level, &quot;:&quot;, lst, i, &quot;-&gt;&quot;, newlst, &quot;=&gt;&quot;, newlist)
				}
			}
		}
		m[level] = newlist
	}
	fmt.Println(m)
}

And the output as below.

map[0:[[0] [1] [2] [3] [4]]]
1 : [0] 1 -&gt; [0 1] =&gt; [[0 1]]
1 : [0] 2 -&gt; [0 2] =&gt; [[0 1] [0 2]]
1 : [0] 3 -&gt; [0 3] =&gt; [[0 1] [0 2] [0 3]]
1 : [0] 4 -&gt; [0 4] =&gt; [[0 1] [0 2] [0 3] [0 4]]
1 : [1] 2 -&gt; [1 2] =&gt; [[0 1] [0 2] [0 3] [0 4] [1 2]]
1 : [1] 3 -&gt; [1 3] =&gt; [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3]]
1 : [1] 4 -&gt; [1 4] =&gt; [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4]]
1 : [2] 3 -&gt; [2 3] =&gt; [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3]]
1 : [2] 4 -&gt; [2 4] =&gt; [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4]]
1 : [3] 4 -&gt; [3 4] =&gt; [[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4] [3 4]]
2 : [0 1] 2 -&gt; [0 1 2] =&gt; [[0 1 2]]
2 : [0 1] 3 -&gt; [0 1 3] =&gt; [[0 1 2] [0 1 3]]
2 : [0 1] 4 -&gt; [0 1 4] =&gt; [[0 1 2] [0 1 3] [0 1 4]]
2 : [0 2] 3 -&gt; [0 2 3] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3]]
2 : [0 2] 4 -&gt; [0 2 4] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4]]
2 : [0 3] 4 -&gt; [0 3 4] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4]]
2 : [1 2] 3 -&gt; [1 2 3] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3]]
2 : [1 2] 4 -&gt; [1 2 4] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4]]
2 : [1 3] 4 -&gt; [1 3 4] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4]]
2 : [2 3] 4 -&gt; [2 3 4] =&gt; [[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]
3 : [0 1 2] 3 -&gt; [0 1 2 3] =&gt; [[0 1 2 3]]
3 : [0 1 2] 4 -&gt; [0 1 2 4] =&gt; [[0 1 2 4] [0 1 2 4]]
3 : [0 1 3] 4 -&gt; [0 1 3 4] =&gt; [[0 1 2 4] [0 1 2 4] [0 1 3 4]]
3 : [0 2 3] 4 -&gt; [0 2 3 4] =&gt; [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4]]
3 : [1 2 3] 4 -&gt; [1 2 3 4] =&gt; [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]
map[4:[] 0:[[0] [1] [2] [3] [4]] 1:[[0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4] [3 4]] 2:[[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]] 3:[[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]]

The issue at here.

3 : [0 1 2] 3 -&gt; [0 1 2 3] =&gt; [[0 1 2 3]]
3 : [0 1 2] 4 -&gt; [0 1 2 4] =&gt; [[0 1 2 4] [0 1 2 4]]           
3 : [0 1 3] 4 -&gt; [0 1 3 4] =&gt; [[0 1 2 4] [0 1 2 4] [0 1 3 4]]
3 : [0 2 3] 4 -&gt; [0 2 3 4] =&gt; [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4]]
3 : [1 2 3] 4 -&gt; [1 2 3 4] =&gt; [[0 1 2 4] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]

The correct output should be:

3 : [0 1 2] 3 -&gt; [0 1 2 3] =&gt; [[0 1 2 3]]
3 : [0 1 2] 4 -&gt; [0 1 2 4] =&gt; [[0 1 2 **3**] [0 1 2 4]]           
3 : [0 1 3] 4 -&gt; [0 1 3 4] =&gt; [[0 1 2 **3**] [0 1 2 4] [0 1 3 4]]
3 : [0 2 3] 4 -&gt; [0 2 3 4] =&gt; [[0 1 2 **3**] [0 1 2 4] [0 1 3 4] [0 2 3 4]]
3 : [1 2 3] 4 -&gt; [1 2 3 4] =&gt; [[0 1 2 **3**] [0 1 2 4] [0 1 3 4] [0 2 3 4] [1 2 3 4]]

I don't know why, but I think it may be a bug of Go compiler or runtime.

What reason of the issue? Maybe a Go bug or just my code mistake. How to solve it if a bug for Go or my code? Cheers!

答案1

得分: 2

在这段代码中,你的切片可能会相互引用:

newlist := make([][]int, 0)
for _, lst := range m[level-1] {
    for i := 0; i < n; i++ {
        if i > lst[len(lst)-1] {
            newlst := append(lst, i)
            newlist = append(newlist, newlst)

你将 i 追加到先前计算的切片中,这可能会重新分配底层数组,也可能不会。当它不重新分配时,每个 newlst 都会重用相同的底层数组,因此在较早版本的 newlst 中,值会被后来的 newlst 覆盖。

你需要通过复制数据来强制新的切片使用新的底层数组:

newlst := append([]int{}, lst...)
newlst = append(newlst, i)

这里是修复后代码的 Playground 版本。

英文:

In this code, your slices may alias each other:

newlist := make([][]int, 0)
for _, lst := range m[level-1] {
    for i := 0; i &lt; n; i++ {
        if i &gt; lst[len(lst)-1] {
            newlst := append(lst, i)
            newlist = append(newlist, newlst)

You're appending i to a previously computed slice, which may or may not reallocate the underlying array. When it doesn't, each newlst reuses the same underlying array, so in earlier versions of newlst, values are overwritten by later versions of newlst.

You need to force the new slices to use new underlying arrays by copying the data:

newlst := append([]int{}, lst...)
newlst = append(newlst, i)

Here's a playground version of the fixed code.

huangapple
  • 本文由 发表于 2017年4月15日 20:15:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/43425951.html
匿名

发表评论

匿名网友

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

确定