英文:
Code to generate powerset in Golang gives wrong result
问题
下面是修复错误并以Go语言惯用方式编写的代码:
package main
import (
"fmt"
)
func main() {
set := []string{"A", "B", "C", "D", "E"}
powerSet := PowerSet(set)
for _, s := range powerSet {
fmt.Println(s)
}
}
func PowerSet(set []string) [][]string {
var powerSet [][]string
powerSet = append(powerSet, []string{})
for _, element := range set {
length := len(powerSet)
for i := 0; i < length; i++ {
newSet := make([]string, len(powerSet[i]))
copy(newSet, powerSet[i])
newSet = append(newSet, element)
powerSet = append(powerSet, newSet)
}
}
return powerSet
}
修复的代码会正确生成幂集,并且使用了Go语言的惯用方式。修复的关键在于在生成新集合时,需要创建一个新的切片并复制现有集合的元素,以避免共享底层数组导致结果错误。
英文:
Next code in Golang to generate powerset produces wrong result on input {"A", "B", "C", "D", "E"}
. I see [A B C E E]
as the last generated set.
<!-- language: go -->
package main
import (
"fmt"
)
func main() {
for _, s := range PowerSet([]string{"A", "B", "C", "D", "E"}) {
fmt.Println(s)
}
}
func PowerSet(set []string) [][]string {
var powerSet [][]string
powerSet = append(powerSet, make([]string, 0))
for _, element := range set {
var moreSets [][]string
for _, existingSet := range powerSet {
newSet := append(existingSet, element)
moreSets = append(moreSets, newSet)
}
powerSet = append(powerSet, moreSets...)
}
return powerSet
}
How to fix it? How to write it idiomatically in Go?
答案1
得分: 3
你的程序问题不在于算法本身,而是这一行代码:
newSet := append(existingSet, element)
你不应该使用append
并将其赋值给另一个变量。
正如文档所述(我强调一下),"append内置函数将元素追加到切片的末尾。如果切片有足够的容量,目标切片将被重新切片以容纳新元素。如果没有足够的容量,将分配一个新的底层数组。"。
因此,可能会出现newSet := append(existingSet, element)
实际上修改了existingSet
本身的情况,这会破坏你的逻辑。
如果你将其改为创建一个新的数组并向其中追加,它将按你的预期工作。
newSet := make([]string, 0)
newSet = append(newSet, existingSet...)
newSet = append(newSet, element)
英文:
The problem with your program is not the algorithm itself but this line:
newSet := append(existingSet, element)
You should not append
and assign to a different variable.
As the documentation states (emphasis mine), "The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated.".
So, there might be cases where newSet := append(existingSet, element)
will actually modify existingSet
itself, which would break your logic.
If you change that to instead create a new array and append to that one, it works as you expect it.
newSet := make([]string, 0)
newSet = append(newSet, existingSet...)
newSet = append(newSet, element)
答案2
得分: 1
例如,您可以使用像这个算法一样的算法:https://stackoverflow.com/a/2779467/3805062。
func PowerSet(original []string) [][]string {
powerSetSize := int(math.Pow(2, float64(len(original))))
result := make([][]string, 0, powerSetSize)
var index int
for index < powerSetSize {
var subSet []string
for j, elem := range original {
if index& (1 << uint(j)) > 0 {
subSet = append(subSet, elem)
}
}
result = append(result, subSet)
index++
}
return result
}
英文:
For instance, you can use algorithm like this one: https://stackoverflow.com/a/2779467/3805062.
func PowerSet(original []string) [][]string {
powerSetSize := int(math.Pow(2, float64(len(original))))
result := make([][]string, 0, powerSetSize)
var index int
for index < powerSetSize {
var subSet []string
for j, elem := range original {
if index& (1 << uint(j)) > 0 {
subSet = append(subSet, elem)
}
}
result = append(result, subSet)
index++
}
return result
}
答案3
得分: 1
以下是翻译好的内容:
详细说明了 @eugenioy 的答案。
请查看此线程。这是一个可工作的示例:https://play.golang.org/p/dzoTk1kimf
func copy_and_append_string(slice []string, elem string) []string {
// 错误:return append(slice, elem)
return append(append([]string(nil), slice...), elem)
}
func PowerSet(s []string) [][]string {
if s == nil {
return nil
}
r := [][]string{[]string{}}
for _, es := range s {
var u [][]string
for _, er := range r {
u = append(u, copy_and_append_string(er, es))
}
r = append(r, u...)
}
return r
}
英文:
Elaborating on @eugenioy's answer.
Look at this thread. Here is a working example : https://play.golang.org/p/dzoTk1kimf
func copy_and_append_string(slice []string, elem string) []string {
// wrong: return append(slice, elem)
return append(append([]string(nil), slice...), elem)
}
func PowerSet(s []string) [][]string {
if s == nil {
return nil
}
r := [][]string{[]string{}}
for _, es := range s {
var u [][]string
for _, er := range r {
u = append(u, copy_and_append_string(er, es))
}
r = append(r, u...)
}
return r
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论