Ruby の Array#repeated_combination
は重複を許す組み合わせを返すメソッドだ(厳密にいうとEnumerator を返す)。
次のブログ記事で見つけた。
cf. 続:Haskell/Clojureでrepeated_combinationを実装してみる – Programmer’s Note
これを Go でやってみよう、ということで Haskell のコードを参考に作ってみた。
package main
import (
"fmt"
)
func main() {
xs := []int{ 1,2,3 }
fmt.Println(repeatedCombination(xs, 3))
}
func repeatedCombination(xs []int, n int) [][]int {
c := make([][]int, 0)
if n == 1 {
for _, x := range xs {
c = append(c, []int{ x })
}
} else {
for _, x := range xs {
for _, y := range repeatedCombination(xs, n - 1) {
c = append(c, append([]int{ x }, y...))
}
}
}
return c
}
ところが、実行結果が Array#repeated_combination
と合わない。
上のコードの実行結果はこう。
^o^ > go run repeated_combination.go
[[1 1 1] [1 1 2] [1 1 3] [1 2 1] [1 2 2] [1 2 3] [1 3 1] [1 3 2] [1 3 3] [2 1 1] [2 1 2] [2 1 3] [2 2 1] [2 2 2] [2 2 3] [2 3 1] [2 3 2] [2 3 3] [3 1 1] [3 1 2] [3 1 3] [3 2 1] [3 2 2] [3 2 3] [3 3 1] [3 3 2] [3 3 3]]
対して Array#repeated_combination
はこう。
irb(main):001:0> [1,2,3].repeated_combination(3).to_a
=> [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 3], [2, 2, 2], [2, 2, 3], [2, 3, 3], [3, 3, 3]]
順列ではなく組み合わせなので、Array#repeated_combination
では例えば [1,1,2] と [1,2,1] と [2,1,1] を同じものとしているのに対して、Go のコードでは別のものとして数え上げてしまっている。
そこで改良を加えたのがこれだ。
package main
import (
"fmt"
)
func main() {
xs := []int{ 1,2,3 }
fmt.Println(repeatedCombination(xs, 3))
}
func repeatedCombination(xs []int, n int) [][]int {
c := make([][]int, 0)
if n == 1 {
for _, x := range xs {
c = append(c, []int{ x })
}
} else {
for _, x := range xs {
for _, y := range repeatedCombination(xs, n - 1) {
if x <= y[0] {
c = append(c, append([]int{ x }, y...))
}
}
}
}
return c
}
実行結果。
^o^ > go run repeated_combination2.go
[[1 1 1] [1 1 2] [1 1 3] [1 2 2] [1 2 3] [1 3 3] [2 2 2] [2 2 3] [2 3 3] [3 3 3]]
今度はうまくいった。