7

I'm looking to find all combinations of single items from a variable number of arrays. How do I do this in Ruby?

Given two arrays, I can use Array.product like this:

groups = []
groups[0] = ["hello", "goodbye"]
groups[1] = ["world", "everyone"]

combinations = groups[0].product(groups[1])

puts combinations.inspect 
# [["hello", "world"], ["hello", "everyone"], ["goodbye", "world"], ["goodbye", "everyone"]]

How could this code work when groups contains a variable number of arrays?

Ollie Glass
  • 19,455
  • 21
  • 76
  • 107

1 Answers1

14
groups = [
  %w[hello goodbye],
  %w[world everyone],
  %w[here there]
]

combinations = groups.first.product(*groups.drop(1))

p combinations
# [
#   ["hello", "world", "here"],
#   ["hello", "world", "there"],
#   ["hello", "everyone", "here"],
#   ["hello", "everyone", "there"],
#   ["goodbye", "world", "here"],
#   ["goodbye", "world", "there"],
#   ["goodbye", "everyone", "here"],
#   ["goodbye", "everyone", "there"]
# ]
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 1
    Wow, thank you. Could you, or someone, possibly explain how this works? – Ollie Glass Aug 05 '10 at 23:37
  • 2
    An explanation of what this actually does would be helpful too, and probably lead to better design of the OP's code... – jtbandes Aug 05 '10 at 23:38
  • 1
    @Ollie: `Array#product` can take multiple arrays as arguments, so this is just basically doing `groups[0].product(groups[1],groups[2],...)` – jtbandes Aug 05 '10 at 23:38
  • 5
    How it works: `product` takes however many arrays you apply to it and gives the Cartesian product of the receiver and all the arguments. The splat operator "expands" an array into a list of arguments, so we take all the arrays in `groups` except the first and pass them as arguments to `product`. – Chuck Aug 05 '10 at 23:43
  • One note, if your `groups` array is truly variable, you have to take into account when it is empty and when it only has 1 array, otherwise you might get `undefined method 'product' for nil:NilClass` – lightswitch05 Aug 21 '13 at 19:17