英文:
Similar Go functions appending strings and arrays do not behave as expected
问题
我有两个Go函数:
func permutation(prefix, str []int) {
n := len(str)
if n == 0 {
fmt.Println(prefix)
} else {
for i := 0; i < n; i++ {
permutation(
append(prefix, str[i]),
append(str[0:i], str[i+1:]...),
)
}
}
}
func perms(prefix, str string) {
n := len(str)
if n == 0 {
fmt.Println(prefix)
} else {
for i := 0; i < n; i++ {
perms(
prefix+string(str[i]),
string(str[0:i])+string(str[i+1:]),
)
}
}
}
第一个函数接受一个整数数组,第二个函数接受一个字符串。它们都计算数组或字符串的所有排列。
你可以这样运行它们:
permutation([]int{}, []int{1, 2, 3})
perms("", "123")
它们的输出不一样:
$ go run main.go
[1 2 3]
[1 3 3]
[3 3 3]
[3 3 3]
[3 3 3]
[3 3 3]
123
132
213
231
312
321
我猜测我可能忽略了一些关于追加数组的细微差别。我似乎无法弄清楚问题所在。你有什么想法吗?
英文:
I have two Go functions:
<!-- language: lang-go -->
func permutation(prefix, str []int) {
n := len(str)
if n == 0 {
fmt.Println(prefix)
} else {
for i := 0; i < n; i++ {
permutation(
append(prefix, str[i]),
append(str[0:i], str[i+1:]...),
)
}
}
}
func perms(prefix, str string) {
n := len(str)
if n == 0 {
fmt.Println(prefix)
} else {
for i := 0; i < n; i++ {
perms(
prefix+string(str[i]),
string(str[0:i])+string(str[i+1:]),
)
}
}
}
The first takes an array of ints, the second takes a string. They both then calculate all permutations of the array, or the string.
I can run them like so:
permutation([]int{}, []int{1, 2, 3})
perms("", "123")
Their output is not the same:
$ go run main.go
[1 2 3]
[1 3 3]
[3 3 3]
[3 3 3]
[3 3 3]
[3 3 3]
123
132
213
231
312
321
I guess there is some nuance to appending arrays that I am missing. I can't seem to figure it out. Any idea what's going on?
答案1
得分: 2
str1+str2
返回一个新的字符串(在内存中与原字符串无关),但append
的行为不同。例如,append(str[0:i], str[i+1:]...)
会破坏str
的原始内容,用str[i+1:]
覆盖str[i:]
。这是因为str[0:i]
有足够的容量来附加str[i+1:]
而不需要分配新的缓冲区。
解决方法是在每次迭代中创建一个全新的数组,至少对于str
来说是这样,因为append(prefix, str[i])
不会受到这个问题的影响。例如:
for i := 0; i < n; i++ {
var s []int
s = append(s, str[0:i]...)
s = append(s, str[i+1:]...)
permutation(append(prefix, str[i]), s)
}
有关切片和append
机制的更多信息,请参考以下链接:
英文:
While str1+str2
does return new (unrelated in terms of memory) string, append
doesn't behave this way. For example append(str[0:i], str[i+1:]...)
will destroy original content of str
, overwriting str[i:]
with str[i+1:]
. This is because str[0:i]
will have capacity to append str[i+1:]
without allocating new buffer.
The solution would be to create a completely new array in every iteration. At least for str
, as append(prefix, str[i])
is immune to this problem. For example:
for i := 0; i < n; i++ {
var s []int
s = append(s, str[0:i]...)
s = append(s, str[i+1:]...)
permutation(append(prefix, str[i]), s)
}
https://play.golang.org/p/lXwu39AA0V
More about slices and mechanism of append:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论