我一直在做一个项目,该项目要求我从一组(复数)数字生成特定长度的所有可能的元组.为此,我try 实现了数学元组[]命令的一个版本,但发现它不能正确生成所有元组.

在经历了许多挫折之后,我发现当我的程序生成长度为4的元组时,它会添加重复项而不是新元素,从而导致任何长度更长的元组都会出现问题.我在网上看了看是否有人有其他类似的问题,然后找到了一些其他代码来完成相同的任务,并注意到我的解决方案与他们的类似.我说不清哪里出错了.

在经历了更多的挫折之后,我发现,如果我将元素预先添加到列表中,一切都很好,只有添加元素才是问题所在.我试图找出我的原始代码出了什么问题,但一无所获.

以下是我为演示该问题而编写的代码.我绝对不是一个专业的程序员,所以如果这不是完成这项任务最惯用的方法,请原谅我.目前,我正在实际代码中使用tuplesByPrepend函数,它工作得很好,我真的只希望了解tuplesByAppend函数出了什么问题.同样,在第三、第五、第八和我测试的任何其他级别,它似乎都做得很好.我可以提供更多关于我的操作系统和构建的信息,如果需要的话.

package main

import "fmt"

func tuplesByAppend[T any](list []T, depth int) [][]T {
    var l1 [][]T
    var l2 [][]T

    for _, v := range list {
        l1 = append(l1, []T{v})
    }

    for i := 1; i < depth; i++ {
        for _, u := range l1 {
            for _, v := range list {
                // Differs here
                next := append(u, v)
                // next is calculated properly, but added to l2 incorrectly at the fourth level only
                // at the fifth level it functions properly
                // fmt.Println(next)
                l2 = append(l2, next)
                // fmt.Println(l2)

                // it appears that at the fourth level it is writing over the previous entries
                // Printing here yields
                // [[1 1 1 1]]
                // [[1 1 1 2] [1 1 1 2]]
                // [[1 1 1 3] [1 1 1 3] [1 1 1 3]]
                // [[1 1 1 3] [1 1 1 3] [1 1 1 3] [1 1 2 1]]
                // [[1 1 1 3] [1 1 1 3] [1 1 1 3] [1 1 2 2] [1 1 2 2]]
                // and so on.
            }
        }
        l1 = l2
        l2 = [][]T{}
    }

    return l1
}

func tuplesByPrepend[T any](list []T, depth int) [][]T {
    var l1 [][]T
    var l2 [][]T

    for _, v := range list {
        l1 = append(l1, []T{v})
    }

    for i := 1; i < depth; i++ {
        for _, u := range l1 {
            for _, v := range list {
                // Differs here
                next := append([]T{v}, u...)
                l2 = append(l2, next)
            }
        }
        l1 = l2
        l2 = [][]T{}
    }

    return l1
}

func main() {
    ourlist := []int{1, 2, 3}
    ourdepth := 4
    appended := tuplesByAppend(ourlist, ourdepth)
    prepended := tuplesByPrepend(ourlist, ourdepth)

    // We should expect this slice to start [1 1 1 1] [1 1 1 2] [1 1 1 3] [1 1 2 1] ...
    // In fact, it starts                   [1 1 1 3] [1 1 1 3] [1 1 1 3] [1 1 2 3]
    fmt.Println(appended)
    // This slice is as expected
    fmt.Println(prepended)
}

推荐答案

在某些情况下,以下代码行的工作方式与您预期的不同:

next := append(u, v)

此示例演示了发生的情况:

package main

import "fmt"

func main() {
    u := append([]int{1, 2}, 3)
    // The length is 3 but the capacity is 4.
    fmt.Printf("u %v\n  len: %d\n  cap: %d\n", u, len(u), cap(u))

    // Since u has enough capacity for the new element "4",
    // v1 will share the same underlying array.
    v1 := append(u, 4)
    fmt.Println("v1:", v1)

    // As what happened to v1, v2 will share the same underlying array too.
    // But the last element "4" in the underlying array is changed to "5".
    v2 := append(u, 5)
    fmt.Println("v2:", v2)

    // Since v1 uses the same underlying array, it sees the change in the last step.
    fmt.Println("v1:", v1)
}

要防止它共享底层数组,请将next := append(u, v)替换为以下代码:

next := make([]T, len(u)+1)
copy(next, u)
next[len(u)] = v

有关详细信息,请参阅Go Slices: usage and internals.

Go相关问答推荐

如何修复Go中调用GetRawInputDeviceInfA Windows API函数时的错误?

创建使用逗号而不是加号分隔OU的CSR

如何配置vscode以在Go中显示不必要的(过度指定的)泛型?

Python样式生成器实现为通道:过早读取

我怎样才能改进这个嵌套逻辑以使其正常工作并提高性能

运行 Docker 容器 - X11 无法打开显示:0

无法在go中为docker容器写入有效的挂载路径

尽管存在 WaitGroup,Goroutines 似乎被打断了

如何以干净的方式在中间件中注入 repo 或服务?

通过环境变量配置 OTLP 导出器

从 Makefile 运行时权限被拒绝

为什么此代码在运行命令 error="exec: not started" 时出现错误?

如何 Select 前 N 个元素 Gin-Gorm

GORM GIN 更新查询导致 500 内部服务器错误

如何从 docker-compose 命令运行 2 个不同的命令:

如何在 Gorm 中获得特定日期的最大值?

Go:为一组单个结果实现 ManyDecode

Go generics:我会在哪里使用 any 而不是 interface{}?

Go 泛型是否与 LINQ to Objects 等效?

Beego - 我需要context.Context而不是 Beego 上下文