Xavier Jacob Xavier Jacob - 1 year ago 49
Ruby Question

How to extract each individual combination from a flat_map?

I'm fairly new to ruby and it's my first question here on stackoverflow so pardon me if I'm being a complete noob.

The code which i am working with contains this line -

puts (6..6).flat_map{|n| ('a'..'z').to_a.combination(n).map(&:join)}

What the code does is that its starts printing each of the combinations starting from "abcdef" and continues till the end (which i have never seen as it has 26^6 combinations).

Of course having an array of that size (26^6) is unimaginable hence I was wondering if there is any way by which i can get next combination in a variable, work with it, and then continue on to the next combination ?

For example I calculate the first combination as "abcdef" and store it in a variable 'combo' and use that variable somewhere and then the next combination is calculated and "abcdeg" is stored in 'combo' and hence the loop continues ?


Answer Source

(6..6).flat_map { |n| ... } doesn't do much. Your code is equivalent to:

puts ('a'..'z').to_a.combination(6).map(&:join)

To process the values one by one, you can pass a block to combination:

('a'..'z').to_a.combination(6) do |combo|
  puts combo.join

If no block is given, combination returns an Enumerator that can be iterated by calling next:

enum = ('a'..'z').to_a.combination(6)
#=> #<Enumerator: ["a", "b", "c", ..., "w", "x", "y", "z"]:combination(6)>

#=> ["a", "b", "c", "d", "e", "f"]

#=> ["a", "b", "c", "d", "e", "g"]

#=> ["a", "b", "c", "d", "e", "h"]

Note that ('a'..'z').to_a.combination(6) will "only" yield 230,230 combinations:

#=> 230230

As opposed to 26 ^ 6 = 308,915,776. You are probably looking for repeated_permutation:

#=> 308915776

Another way to iterate from "aaaaaa" to "zzzzzz" is a simple range:

('aaaaaa'..'zzzzzz').each do |combo|
   puts combo

Or manually by calling String#succ: (this is what Range#each does under the hood)

'aaaaaa'.succ #=> "aaaaab"
'aaaaab'.succ #=> "aaaaac"

'aaaaaz'.succ #=> "aaaaba"