Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the equivalent of Python's itertools.product in Ruby?

I'm looking for a method that has the same effect as Python's itertools.product in 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

That outputs something like this:

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

I tried to translate that 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 output isn't the same. The one-character ones work fine (a-z), but when it goes into two-character ones, it doesn't work as I expected:

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

It isn't generating aa, ba or bb - so it appears it's generating all the combinations without repeating characters or something?

So what method should I use to generate all the combinations like itertools.product does in Python?

like image 403
Alex Coplan Avatar asked Dec 28 '22 02:12

Alex Coplan


2 Answers

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

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"]

A lazy solution: you could easily write it with eachs instead of maps, but let's check "lazy" from 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
like image 195
tokland Avatar answered Apr 27 '23 00:04

tokland


You have Array#product which is like itertools.product.

like image 30
luis.parravicini Avatar answered Apr 26 '23 23:04

luis.parravicini