What is equivalent to Python itertools.product in Ruby?

I am looking for a method that has the same effect as Python itertools.productin Ruby. Take the following Python code:

from itertools import product

chars = []
for i in range(97,123):
    chars.append(chr(i))

for a in range(1,3):
    for i in product(chars,repeat=a):
        s = ''.join(i)
        print s

This outputs something like this:

a, b, c... x, y, z, aa, ab, ac... ax, ay, az, ba, bb, bc.. etc.

I tried translating this into Ruby:

(1..2).each do |n|
  ('a'..'z').to_a.combination(n).each do |c|
    s = c.join
    puts s
  end
end

But the result is not the same. The single-character ones work fine (az), but when it goes into the two-character one, it doesn't work as I expected:

ab, ac, ad.. ax, ay, az, bc, bd, be

It does not generate aa, baor bb- does it mean that it generates all combinations without repeating characters or something else?

So, which method should be used to create all combinations, such as itertools.product, in Python?

+3
source share
6 answers

I would write (simplified for 3 elements, requires Ruby 1.9):

xs = ["a", "b", "c"]
strings = 1.upto(xs.size).flat_map do |n| 
  xs.repeated_permutation(n).map(&:join)
end
#=> ["a", "b", "c", "aa", "ab", "ac", ...,  "cca", "ccb", "ccc"]

: each map s, "" Ruby 2.0:

xs = ("a".."z").to_a
strings = 1.upto(xs.size).lazy.flat_map do |n| 
  xs.repeated_permutation(n).lazy.map(&:join)
end
+3

( ):

a = ('a'..'z').to_a
result = (0..2).map { |n| 
  a.product(*n.times.inject([]) { |s,x| s << a }) }.map { |x| x.map(&:join) } 
}

puts result

: product n-1 product.

, product('abc', repeat=n) Ruby :

a = ['a','b','c']
a.product()     # n = 1
a.product(a)    # n = 2
a.product(a, a) # n = 3

, inject . . , , "".

+2

, , , . , .

arr = ['a', 'b', 'c']

p (0..2).inject([]) { |acc, a|
  acc + arr.product(*[arr]*a).map(&:join)
}

=> ["a", "b", "c", "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc", "aaa", "aab", "aac", "aba", "abb", "abc", "aca", "acb", "acc", "baa", "bab", "bac", "bba", "bbb", "bbc", "bca", "bcb", "bcc", "caa", "cab", "cac", "cba", "cbb", "cbc", "cca", "ccb", "ccc"]

"gotchas"

  • *[arr]*a, a arr s, a product.
  • map(&:join), map{|e| e.join}
  • inject (in other words, “reduce”, from a “weak card”), one of the pillars of FP
+1
source

In ruby, Array # leads to Cathesian. Adding the original array will give the same results.

ar = (?a..?z).to_a
ar + ar.product(ar).map(&:join)
+1
source

Using tokland, I have this:

(1..2).each do |n|
  ('a'..'z').to_a.repeated_permutation(n).each do |a|
    s = a.join
    puts s
  end
end

And it is lazy, so it does not start RAM when you use it to generate longer lines.

0
source

All Articles