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

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

Implement Ruby style Cartesian product in Go

问题

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

a = ['a1']
b = ['b1', 'b2']
c = ['c1', 'c2', 'c3']
d = ['d1']

以下是Ruby代码:

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

输出结果为:

[
  ["a1", "b1", "c1", "d1"],
  ["a1", "b1", "c2", "d1"],
  ["a1", "b1", "c3", "d1"],
  ["a1", "b2", "c1", "d1"],
  ["a1", "b2", "c2", "d1"],
  ["a1", "b2", "c3", "d1"]
]

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

英文:

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

a = ['a1']
b = ['b1', 'b2']
c = ['c1', 'c2', 'c3']
d = ['d1']

Here is code in Ruby:

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

Output is:

[
  ["a1", "b1", "c1", "d1"],
  ["a1", "b1", "c2", "d1"],
  ["a1", "b1", "c3", "d1"],
  ["a1", "b2", "c1", "d1"],
  ["a1", "b2", "c2", "d1"],
  ["a1", "b2", "c3", "d1"]
]

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

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

package main

import "fmt"

// NextIndex将ix设置为字典顺序的下一个值,
// 对于每个i>0,0 <= ix[i] < lens(i)。
func NextIndex(ix []int, lens func(i int) int) {
    for j := len(ix) - 1; j >= 0; j-- {
        ix[j]++
        if j == 0 || ix[j] < lens(j) {
            return
        }
        ix[j] = 0
    }
}

func main() {
    e := [][]string{
        {"a1"},
        {"b1", "b2"},
        {"c1", "c2", "c3"},
        {"d1"},
    }
    lens := func(i int) int { return len(e[i]) }

    for ix := make([]int, len(e)); ix[0] < lens(0); NextIndex(ix, lens) {
        var r []string
        for j, k := range ix {
            r = append(r, e[j][k])
        }
        fmt.Println(r)
    }
}

输出结果为:

[a1 b1 c1 d1]
[a1 b1 c2 d1]
[a1 b1 c3 d1]
[a1 b2 c1 d1]
[a1 b2 c2 d1]
[a1 b2 c3 d1]
英文:

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

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(i).
func NextIndex(ix []int, lens func(i int) int) {
	for j := len(ix) - 1; j &gt;= 0; j-- {
		ix[j]++
		if j == 0 || ix[j] &lt; lens(j) {
			return
		}
		ix[j] = 0
	}
}

func main() {
	e := [][]string{
		{&quot;a1&quot;},
		{&quot;b1&quot;, &quot;b2&quot;},
		{&quot;c1&quot;, &quot;c2&quot;, &quot;c3&quot;},
		{&quot;d1&quot;},
	}
	lens := func(i int) int { return len(e[i]) }

	for ix := make([]int, len(e)); ix[0] &lt; lens(0); NextIndex(ix, lens) {
		var r []string
		for j, k := range ix {
			r = append(r, e[j][k])
		}
		fmt.Println(r)
	}
}

The output is:

[a1 b1 c1 d1]
[a1 b1 c2 d1]
[a1 b1 c3 d1]
[a1 b2 c1 d1]
[a1 b2 c2 d1]
[a1 b2 c3 d1]

答案2

得分: 2

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

// cartesianProduct返回给定矩阵的笛卡尔积
func cartesianProduct[T any](matrix [][]T) [][]T {
    // nextIndex将ix设置为字典序的下一个值,
    // 对于每个i>0,0 <= ix[i] < lens(i)。
    nextIndex := func(ix []int, lens func(i int) int) {
        for j := len(ix) - 1; j >= 0; j-- {
            ix[j]++

            if j == 0 || ix[j] < lens(j) {
                return
            }

            ix[j] = 0
        }
    }

    lens := func(i int) int { return len(matrix[i]) }

    results := make([][]T, 0, len(matrix))
    for indexes := make([]int, len(matrix)); indexes[0] < lens(0); nextIndex(indexes, lens) {
        var temp []T

        for j, k := range indexes {
            temp = append(temp, matrix[j][k])
        }

        results = append(results, temp)
    }

    return results
}
英文:

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

// cartesianProduct returns the cartesian product
// of a given matrix
func cartesianProduct[T any](matrix [][]T) [][]T {
	// nextIndex sets ix to the lexicographically next value,
	// such that for each i&gt;0, 0 &lt;= ix[i] &lt; lens(i).
	nextIndex := func(ix []int, lens func(i int) int) {
		for j := len(ix) - 1; j &gt;= 0; j-- {
			ix[j]++

			if j == 0 || ix[j] &lt; lens(j) {
				return
			}

			ix[j] = 0
		}
	}

	lens := func(i int) int { return len(matrix[i]) }

	results := make([][]T, 0, len(matrix))
	for indexes := make([]int, len(matrix)); indexes[0] &lt; lens(0); nextIndex(indexes, lens) {
		var temp []T

		for j, k := range indexes {
			temp = append(temp, matrix[j][k])
		}

		results = append(results, temp)
	}

	return results
}

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:

确定