如何创建笛卡尔积?

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

How to create cartesian product

问题

我有一个整数列表 a = [0, ..., n]。我想要生成从a中选择k个元素的所有可能组合;也就是a自身的笛卡尔积,重复k次。请注意,n和k都可以在运行时更改,所以这个函数需要是可调整的。

所以如果n是3,k是2:

a = [0, 1, 2, 3]
k = 2

desired = [(0,0), (0, 1), (0, 2), ..., (2,3), (3,0), ..., (3,3)]

在Python中,我会使用itertools.product()函数:

for p in itertools.product(a, repeat=2):
    print p

在Go语言中,有什么惯用的方法来做到这一点?

初步的想法是使用闭包返回一个整数切片,但感觉不太简洁。

英文:

I have a list of integers, a = [0, ..., n]. I want to generate all possible combinations of k elements from a; i.e., the cartesian product of the a with itself k times. Note that n and k are both changeable at runtime, so this needs to be at least a somewhat adjustable function.

So if n was 3, and k was 2:

a = [0, 1, 2, 3]
k = 2

desired = [(0,0), (0, 1), (0, 2), ..., (2,3), (3,0), ..., (3,3)]

In python I would use the itertools.product() function:

for p in itertools.product(a, repeat=2):
    print p

What's an idiomatic way to do this in Go?

Initial guess is a closure that returns a slice of integers, but it doesn't feel very clean.

答案1

得分: 7

例如,

package main

import "fmt"

func nextProduct(a []int, r int) func() []int {
    p := make([]int, r)
    x := make([]int, len(p))
    return func() []int {
        p := p[:len(x)]
        for i, xi := range x {
            p[i] = a[xi]
        }
        for i := len(x) - 1; i >= 0; i-- {
            x[i]++
            if x[i] < len(a) {
                break
            }
            x[i] = 0
            if i <= 0 {
                x = x[0:0]
                break
            }
        }
        return p
    }
}

func main() {
    a := []int{0, 1, 2, 3}
    k := 2
    np := nextProduct(a, k)
    for {
        product := np()
        if len(product) == 0 {
            break
        }
        fmt.Println(product)
    }
}

输出:

[0 0]
[0 1]
[0 2]
[0 3]
[1 0]
[1 1]
[1 2]
[1 3]
[2 0]
[2 1]
[2 2]
[2 3]
[3 0]
[3 1]
[3 2]
[3 3]
英文:

For example,

package main

import &quot;fmt&quot;

func nextProduct(a []int, r int) func() []int {
	p := make([]int, r)
	x := make([]int, len(p))
	return func() []int {
		p := p[:len(x)]
		for i, xi := range x {
			p[i] = a[xi]
		}
		for i := len(x) - 1; i &gt;= 0; i-- {
			x[i]++
			if x[i] &lt; len(a) {
				break
			}
			x[i] = 0
			if i &lt;= 0 {
				x = x[0:0]
				break
			}
		}
		return p
	}
}

func main() {
	a := []int{0, 1, 2, 3}
	k := 2
	np := nextProduct(a, k)
	for {
		product := np()
		if len(product) == 0 {
			break
		}
		fmt.Println(product)
	}
}

Output:

[0 0]
[0 1]
[0 2]
[0 3]
[1 0]
[1 1]
[1 2]
[1 3]
[2 0]
[2 1]
[2 2]
[2 3]
[3 0]
[3 1]
[3 2]
[3 3]

答案2

得分: 3

找到按字典顺序的下一个产品的代码很简单:从右边开始,找到第一个在递增时不会溢出的值,将其递增并将右边的值归零。

package main

import "fmt"

func main() {
    n, k := 5, 2
    ix := make([]int, k)
    for {
        fmt.Println(ix)
        j := k - 1
        for ; j >= 0 && ix[j] == n-1; j-- {
            ix[j] = 0
        }
        if j < 0 {
            return
        }
        ix[j]++
    }
}

我将“n”更改为表示集合[0, 1, ..., n-1],而不是问题中给出的[0, 1, ..., n],因为后者会导致混淆,因为它有n+1个元素。

英文:

The code to find the next product in lexicographic order is simple: starting from the right, find the first value that won't roll over when you increment it, increment that and zero the values to the right.

package main

import &quot;fmt&quot;

func main() {
	n, k := 5, 2
	ix := make([]int, k)
	for {
		fmt.Println(ix)
		j := k - 1
		for ; j &gt;= 0 &amp;&amp; ix[j] == n-1; j-- {
			ix[j] = 0
		}
		if j &lt; 0 {
			return
		}
		ix[j]++
	}
}

I've changed "n" to mean the set is [0, 1, ..., n-1] rather than [0, 1, ..., n] as given in the question, since the latter is confusing since it has n+1 elements.

答案3

得分: 1

只需按照以下链接中的答案进行操作:https://stackoverflow.com/questions/29002724/implement-ruby-style-cartesian-product-in-go,并在http://play.golang.org/p/NR1_3Fsq8F上运行它。

package main

import "fmt"

// NextIndex sets ix to the lexicographically next value,
// such that for each i>0, 0 <= ix[i] < lens.
func NextIndex(ix []int, lens int) {
    for j := len(ix) - 1; j >= 0; j-- {
        ix[j]++
        if j == 0 || ix[j] < lens {
            return
        }
        ix[j] = 0
    }
}

func main() {
    a := []int{0, 1, 2, 3}
    k := 2
    lens := len(a)
    r := make([]int, k)
    for ix := make([]int, k); ix[0] < lens; NextIndex(ix, lens) {
        for i, j := range ix {
            r[i] = a[j]
        }
        fmt.Println(r)
    }
}

希望对你有帮助!

英文:

Just follow the answer https://stackoverflow.com/questions/29002724/implement-ruby-style-cartesian-product-in-go, play it on http://play.golang.org/p/NR1_3Fsq8F

package main

import &quot;fmt&quot;

// NextIndex sets ix to the lexicographically next value,
// such that for each i&gt;0, 0 &lt;= ix[i] &lt; lens.
func NextIndex(ix []int, lens int) {
	for j := len(ix) - 1; j &gt;= 0; j-- {
		ix[j]++
		if j == 0 || ix[j] &lt; lens {
			return
		}
		ix[j] = 0
	}
}

func main() {
	a := []int{0, 1, 2, 3}
	k := 2
	lens := len(a)
	r := make([]int, k)
	for ix := make([]int, k); ix[0] &lt; lens; NextIndex(ix, lens) {
		for i, j := range ix {
			r[i] = a[j]
		}
		fmt.Println(r)
	}
}

huangapple
  • 本文由 发表于 2014年5月2日 00:37:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/23412146.html
匿名

发表评论

匿名网友

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

确定