In Ruby we have permutations and combinations procs for arrays, and variants
with repetition.
I have not found too much of this for Nim yet, so I tried myself:
# https://ruby-doc.org/core-2.4.0/Array.html#method-i-repeated_combination
# https://rosettacode.org/wiki/Combinations
#
http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n
proc repeatedPermutations[T](a: openarray[T], n: int): seq[seq[T]] =
result = newSeq[seq[T]]()
if n <= 0: return
for i in 0 .. a.high:
if n == 1:
result.add(@[a[i]])
else:
for j in repeatedPermutations(a, n - 1):
result.add(a[i] & j)
proc perm[T](a: openarray[T], n: int, use: var seq[bool]): seq[seq[T]] =
result = newSeq[seq[T]]()
if n <= 0: return
for i in 0 .. a.high:
if not use[i]:
if n == 1:
result.add(@[a[i]])
else:
use[i] = true
for j in perm(a, n - 1, use):
result.add(a[i] & j)
use[i] = false
proc permutations[T](a: openarray[T], n: int): seq[seq[T]] =
var use = newSeq[bool](a.len)
perm(a, n, use)
proc comb[T](a: openarray[T]; n: int; use: seq[bool]): seq[seq[T]] =
result = newSeq[seq[T]]()
var use = use
if n <= 0: return
for i in 0 .. a.high:
if not use[i]:
if n == 1:
result.add(@[a[i]])
else:
use[i] = true
for j in comb(a, n - 1, use):
result.add(a[i] & j)
proc combinations[T](a: openarray[T], n: int): seq[seq[T]] =
var use = newSeq[bool](a.len)
comb(a, n, use)
proc rcomb[T](a: openarray[T]; n: int; use: seq[bool]): seq[seq[T]] =
result = newSeq[seq[T]]()
var use = use
if n <= 0: return
for i in 0 .. a.high:
if not use[i]:
if n == 1:
result.add(@[a[i]])
else:
for j in rcomb(a, n - 1, use):
result.add(a[i] & j)
use[i] = true
proc repeatedCombinations[T](a: openarray[T], n: int): seq[seq[T]] =
var use = newSeq[bool](a.len)
rcomb(a, n, use)
# now we try to make an iterator
iterator repeatedPermutation[T](a: openarray[T], n: int): seq[T] =
for i in 0 .. a.high:
if n == 1:
yield @[a[i]]
else:
for j in repeatedPermutations(a, n - 1):
for k in j:
yield @[a[i]] & k
when isMainModule:
let ar = [1, 2, 3, 4]
let ll = 2
echo "Permutations"
echo permutations(ar, ll)
echo "repeated Permutations"
echo repeatedPermutations(ar, ll)
echo "repeated Combinations"
echo repeatedCombinations(ar, ll)
echo "combinations"
echo combinations(ar, ll)
let arr = ['A', 'B', 'C', 'D']
echo "Permutations"
echo permutations(arr, ll)
echo "repeated Permutations"
echo repeatedPermutations(arr, ll)
echo "repeated Combinations"
echo repeatedCombinations(arr, ll)
echo "combinations"
echo combinations(arr, ll)
echo "repeated Permutation Iterator"
for i in repeatedPermutation(ar, ll): echo i
$ ./fun | sed 's/@//g'
Permutations
[[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4],
[4, 1], [4, 2], [4, 3]]
repeated Permutations
[[1, 1], [1, 2], [1, 3], [1, 4], [2, 1], [2, 2], [2, 3], [2, 4], [3, 1],
[3, 2], [3, 3], [3, 4], [4, 1], [4, 2], [4, 3], [4, 4]]
repeated Combinations
[[1, 1], [1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [2, 4], [3, 3], [3, 4],
[4, 4]]
combinations
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
Permutations
[[A, B], [A, C], [A, D], [B, A], [B, C], [B, D], [C, A], [C, B], [C, D],
[D, A], [D, B], [D, C]]
repeated Permutations
[[A, A], [A, B], [A, C], [A, D], [B, A], [B, B], [B, C], [B, D], [C, A],
[C, B], [C, C], [C, D], [D, A], [D, B], [D, C], [D, D]]
repeated Combinations
[[A, A], [A, B], [A, C], [A, D], [B, B], [B, C], [B, D], [C, C], [C, D],
[D, D]]
combinations
[[A, B], [A, C], [A, D], [B, C], [B, D], [C, D]]
repeated Permutation Iterator
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[4, 1]
[4, 2]
[4, 3]
[4, 4]
Output seems to be identical to Ruby results.
First question: Is all that already available somewhere?
Next: Is it a stupid solution?
And last: How to convert that to iterators? I have managed that somehow for the
simplest case, but the iterator calls the proc with same name. And for the
other procs it is more difficult because each exported proc calls a local child.