为什么切片值会改变?

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

Why does slice value change?

问题

被附加到二维切片的切片的值稍后发生了变化。为什么会这样呢?

完整的代码如下:

import "sort"
import "fmt"

func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    var ret [][]int
    var curlist []int
    combinationSumRecursive(candidates, target, 0, curlist, &ret)
    fmt.Println("ret", ret)
    return ret
}

func combinationSumRecursive(candidates []int, target int, curCandidateIdx int, curlist []int, ret *[][]int) {
    if target == 0 {
        fmt.Println("put", curlist)
        *ret = append(*ret, curlist)
        return
    }
    for i := curCandidateIdx; i < len(candidates); i++ {
        if candidates[i] > target {
            break
        }
        combinationSumRecursive(candidates, target-candidates[i], i, append(curlist, candidates[i]), ret)
    }
}

输入为:

[7,3,2]
18

输出如下:

put [2 2 2 2 2 2 2 2 2]
put [2 2 2 2 2 2 3 3]
put [2 2 2 2 3 7]
put [2 2 2 3 3 3 3]
put [2 2 7 7]
put [2 3 3 3 7]
put [3 3 3 3 3 3]
ret [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 7 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

ret 中的第二个切片发生了变化。预期是 [2 2 2 2 2 2 3 3]

谢谢任何帮助。

英文:

The value of a slice that be appended to a two-dimension slice, is changed later。 Why does it happen?

The full code is below:

import &quot;sort&quot;
import &quot;fmt&quot;

func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    var ret [][]int
    var curlist []int
    combinationSumRecursive(candidates, target, 0, curlist, &amp;ret)
    fmt.Println(&quot;ret&quot;, ret)
    return ret
}

func combinationSumRecursive(candidates []int, target int, curCandidateIdx int, curlist []int, ret *[][]int) {
    if target == 0 {
        fmt.Println(&quot;put&quot;, curlist)
        *ret = append(*ret, curlist)
        return
    }
    for i:=curCandidateIdx;i&lt;len(candidates);i++{
        if candidates[i] &gt; target {
            break
        }
        combinationSumRecursive(candidates, target - candidates[i], i, append(curlist, candidates[i]), ret)
    }
}

INPUT is :

[7,3,2]
18

OUTPUT is below:

put [2 2 2 2 2 2 2 2 2]
put [2 2 2 2 2 2 3 3]
put [2 2 2 2 3 7]
put [2 2 2 3 3 3 3]
put [2 2 7 7]
put [2 3 3 3 7]
put [3 3 3 3 3 3]
ret [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 7 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

The second slice in ret is changed. [2 2 2 2 2 2 3 3] was expected.

Thanks to any help.

答案1

得分: 1

这是由于在第combinationSumRecursive(candidates, target - candidates[i], i, append(curlist, candidates[i]), ret)行的追加操作中,切片curlist的改变导致的。

解决方法是在将其传递给下一个递归级别之前,将curlist重新分配为追加的结果。

package main

import "sort"
import "fmt"

func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    var ret [][]int
    var curlist []int
    combinationSumRecursive(candidates, target, 0, curlist, &ret)
    fmt.Println("ret", ret)
    return ret
}

func combinationSumRecursive(candidates []int, target int, curCandidateIdx int, curlist []int, ret *[][]int) {
    if target == 0 {
        fmt.Println("put", curlist)
        *ret = append(*ret, append([]int(nil), curlist...))
        return
    }
    for i := curCandidateIdx; i < len(candidates); i++ {
        if candidates[i] > target {
            break
        }
        curlist = append(curlist, candidates[i])
        combinationSumRecursive(candidates, target-candidates[i], i, curlist, ret)
        curlist = curlist[:len(curlist)-1]
    }
}

func main() {
    combinationSum([]int{7, 3, 2}, 18)
}

这将产生以下结果:

put [2 2 2 2 2 2 2 2 2]
put [2 2 2 2 2 2 3 3]
put [2 2 2 2 3 7]
put [2 2 2 3 3 3 3]
put [2 2 7 7]
put [2 3 3 3 7]
put [3 3 3 3 3 3]
ret [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

[编辑] 首先阅读这篇文章。它解释了尽管您看到切片头的地址发生了变化,但追加后的支持数组仍然可能是相同的。

然后,这篇文章是您的情况下发生的示例。
问题在于在您的情况下,由于递归调用和将当前索引重新定位到curlist中,很难看到这一点。

英文:

This is caused by the change of the slice curlist in the append on line combinationSumRecursive(candidates, target - candidates[i], i, append(curlist, candidates[i]), ret).

A solution is to reassign curlist to the appended result before passing it to the next recursive level.

package main

import &quot;sort&quot;
import &quot;fmt&quot;

func combinationSum(candidates []int, target int) [][]int {
	sort.Ints(candidates)
	var ret [][]int
	var curlist []int
	combinationSumRecursive(candidates, target, 0, curlist, &amp;ret)
	fmt.Println(&quot;ret&quot;, ret)
	return ret
}

func combinationSumRecursive(candidates []int, target int, curCandidateIdx int, curlist []int, ret *[][]int) {
	if target == 0 {
		fmt.Println(&quot;put&quot;, curlist)
		*ret = append(*ret, curlist)
		return
	}
	for i := curCandidateIdx; i &lt; len(candidates); i++ {
		if candidates[i] &gt; target {
			break
		}
		curlist = append(curlist, candidates[i])
		combinationSumRecursive(candidates, target-candidates[i], i, curlist, ret)
	}
}

func main() {
	combinationSum([]int{7, 3, 2}, 18)
}

This yields:

put [2 2 2 2 2 2 2 2 2]
put [2 2 2 2 2 2 3 3]
put [2 2 2 2 3 7]
put [2 2 2 3 3 3 3]
put [2 2 7 7]
put [2 3 3 3 7]
put [3 3 3 3 3 3]
ret [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

[EDIT] First read this. That explains that although you see the addresses of the slice headers change the backing array can still be the same after an append.

Then this is an example of what happens in your case.
The problem is in your case is it hard to see because of the recursive calls and the re positioning of the current index into curlist.

答案2

得分: 1

你只在target==0时打印curlist,但由于递归函数中的append(curlist, candidates[i])curlist会不断变化。
如果你尝试使用其他候选项,例如:[5,3,2],你会注意到其他切片不仅仅是第二个切片会改变。

target=0时,尝试复制curlist

if target == 0 {
    fmt.Println("put", curlist)
    newCurlist := make([]int, len(curlist))
    copy(newCurlist, curlist)
    *ret = append(*ret, newCurlist)
    return
}

这样应该可以解决问题!

英文:

You're printing the curlist only when target==0 but it keeps changing due to the append(curlist, candidates[i]) in your recursive function.
If you try with other candidates, for example : [5,3,2] you will notice that other slices change not only the second.

try making a copy of curlist when the target=0:

if target == 0 {
	fmt.Println(&quot;put&quot;, curlist)
	newCurlist := make([]int, len(curlist))
	copy(newCurlist, curlist)
	*ret = append(*ret, newCurlist)
	return
}

this should work!

huangapple
  • 本文由 发表于 2017年3月3日 14:57:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/42572569.html
匿名

发表评论

匿名网友

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

确定