在Go中实现Ruby风格的笛卡尔积。

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

Implement Ruby style Cartesian product in Go

问题

我想要获取abcd的笛卡尔积:

  1. a = ['a1']
  2. b = ['b1', 'b2']
  3. c = ['c1', 'c2', 'c3']
  4. d = ['d1']

以下是Ruby代码:

  1. e = [b, c, d]
  2. print a.product(*e)

输出结果为:

  1. [
  2. ["a1", "b1", "c1", "d1"],
  3. ["a1", "b1", "c2", "d1"],
  4. ["a1", "b1", "c3", "d1"],
  5. ["a1", "b2", "c1", "d1"],
  6. ["a1", "b2", "c2", "d1"],
  7. ["a1", "b2", "c3", "d1"]
  8. ]

在Golang中是否有类似的包或函数可以实现笛卡尔积?这只是一个简化版本,实际上输入数据可能是这样的:[['a1'], ['b1','b2'], ['c1','c2','c3'],['d1'],['e1',...],...]。

英文:

I want to get the Cartesian product of a, b, c, d:

  1. a = ['a1']
  2. b = ['b1', 'b2']
  3. c = ['c1', 'c2', 'c3']
  4. d = ['d1']

Here is code in Ruby:

  1. e = [b, c, d]
  2. print a.product(*e)

Output is:

  1. [
  2. ["a1", "b1", "c1", "d1"],
  3. ["a1", "b1", "c2", "d1"],
  4. ["a1", "b1", "c3", "d1"],
  5. ["a1", "b2", "c1", "d1"],
  6. ["a1", "b2", "c2", "d1"],
  7. ["a1", "b2", "c3", "d1"]
  8. ]

Is there a similar package or function that could do product in Golang?
This is just simplified version, in fact, the input data is like [['a1'], ['b1','b2'], ['c1','c2','c3],['d1'],['e1',...],...].

答案1

得分: 8

如果您需要在编译时未知的嵌套索引循环集,可以使用以下代码:

  1. package main
  2. import "fmt"
  3. // NextIndex将ix设置为字典顺序的下一个值,
  4. // 对于每个i>0,0 <= ix[i] < lens(i)。
  5. func NextIndex(ix []int, lens func(i int) int) {
  6. for j := len(ix) - 1; j >= 0; j-- {
  7. ix[j]++
  8. if j == 0 || ix[j] < lens(j) {
  9. return
  10. }
  11. ix[j] = 0
  12. }
  13. }
  14. func main() {
  15. e := [][]string{
  16. {"a1"},
  17. {"b1", "b2"},
  18. {"c1", "c2", "c3"},
  19. {"d1"},
  20. }
  21. lens := func(i int) int { return len(e[i]) }
  22. for ix := make([]int, len(e)); ix[0] < lens(0); NextIndex(ix, lens) {
  23. var r []string
  24. for j, k := range ix {
  25. r = append(r, e[j][k])
  26. }
  27. fmt.Println(r)
  28. }
  29. }

输出结果为:

  1. [a1 b1 c1 d1]
  2. [a1 b1 c2 d1]
  3. [a1 b1 c3 d1]
  4. [a1 b2 c1 d1]
  5. [a1 b2 c2 d1]
  6. [a1 b2 c3 d1]
英文:

If you need an unknown-at-compile-time set of nested index loops, you can use code like this.

  1. package main
  2. import &quot;fmt&quot;
  3. // NextIndex sets ix to the lexicographically next value,
  4. // such that for each i&gt;0, 0 &lt;= ix[i] &lt; lens(i).
  5. func NextIndex(ix []int, lens func(i int) int) {
  6. for j := len(ix) - 1; j &gt;= 0; j-- {
  7. ix[j]++
  8. if j == 0 || ix[j] &lt; lens(j) {
  9. return
  10. }
  11. ix[j] = 0
  12. }
  13. }
  14. func main() {
  15. e := [][]string{
  16. {&quot;a1&quot;},
  17. {&quot;b1&quot;, &quot;b2&quot;},
  18. {&quot;c1&quot;, &quot;c2&quot;, &quot;c3&quot;},
  19. {&quot;d1&quot;},
  20. }
  21. lens := func(i int) int { return len(e[i]) }
  22. for ix := make([]int, len(e)); ix[0] &lt; lens(0); NextIndex(ix, lens) {
  23. var r []string
  24. for j, k := range ix {
  25. r = append(r, e[j][k])
  26. }
  27. fmt.Println(r)
  28. }
  29. }

The output is:

  1. [a1 b1 c1 d1]
  2. [a1 b1 c2 d1]
  3. [a1 b1 c3 d1]
  4. [a1 b2 c1 d1]
  5. [a1 b2 c2 d1]
  6. [a1 b2 c3 d1]

答案2

得分: 2

根据@paul-hankin的答案,这里有一个嵌入函数并使用泛型的解决方案。需要最低的go 1.18版本。

  1. // cartesianProduct返回给定矩阵的笛卡尔积
  2. func cartesianProduct[T any](matrix [][]T) [][]T {
  3. // nextIndex将ix设置为字典序的下一个值,
  4. // 对于每个i>0,0 <= ix[i] < lens(i)。
  5. nextIndex := func(ix []int, lens func(i int) int) {
  6. for j := len(ix) - 1; j >= 0; j-- {
  7. ix[j]++
  8. if j == 0 || ix[j] < lens(j) {
  9. return
  10. }
  11. ix[j] = 0
  12. }
  13. }
  14. lens := func(i int) int { return len(matrix[i]) }
  15. results := make([][]T, 0, len(matrix))
  16. for indexes := make([]int, len(matrix)); indexes[0] < lens(0); nextIndex(indexes, lens) {
  17. var temp []T
  18. for j, k := range indexes {
  19. temp = append(temp, matrix[j][k])
  20. }
  21. results = append(results, temp)
  22. }
  23. return results
  24. }
英文:

Based on @paul-hankin answer, here a solution which is embedded in a function and uses generics. Needs go 1.18 minimum

  1. // cartesianProduct returns the cartesian product
  2. // of a given matrix
  3. func cartesianProduct[T any](matrix [][]T) [][]T {
  4. // nextIndex sets ix to the lexicographically next value,
  5. // such that for each i&gt;0, 0 &lt;= ix[i] &lt; lens(i).
  6. nextIndex := func(ix []int, lens func(i int) int) {
  7. for j := len(ix) - 1; j &gt;= 0; j-- {
  8. ix[j]++
  9. if j == 0 || ix[j] &lt; lens(j) {
  10. return
  11. }
  12. ix[j] = 0
  13. }
  14. }
  15. lens := func(i int) int { return len(matrix[i]) }
  16. results := make([][]T, 0, len(matrix))
  17. for indexes := make([]int, len(matrix)); indexes[0] &lt; lens(0); nextIndex(indexes, lens) {
  18. var temp []T
  19. for j, k := range indexes {
  20. temp = append(temp, matrix[j][k])
  21. }
  22. results = append(results, temp)
  23. }
  24. return results
  25. }

huangapple
  • 本文由 发表于 2015年3月12日 13:49:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/29002724.html
匿名

发表评论

匿名网友

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

确定