Given an array of size y, containing arrays of size n, how can I return all logical combinations using Ruby?

arrays, ruby

Solution

It looks like you want to compute the cartesian product of the arrays. The method which computes the cartesian product is (not too surprisingly) called `Array#product`:

@task_states.first.product(*@task_states.drop(1))

So, for example:

['A', 'no A'].product(['B', 'no B'], ['C', 'no C'], ['D', 'no D'])
#=> [[   "A",    "B",    "C",    "D"],
#    [   "A",    "B",    "C", "no D"],
#    [   "A",    "B", "no C",    "D"],
#    [   "A",    "B", "no C", "no D"],
#    [   "A", "no B",    "C",    "D"],
#    [   "A", "no B",    "C", "no D"],
#    [   "A", "no B", "no C",    "D"],
#    [   "A", "no B", "no C", "no D"],
#    ["no A",    "B",    "C",    "D"],
#    ["no A",    "B",    "C", "no D"],
#    ["no A",    "B", "no C",    "D"],
#    ["no A",    "B", "no C", "no D"],
#    ["no A", "no B",    "C",    "D"],
#    ["no A", "no B",    "C", "no D"],
#    ["no A", "no B", "no C",    "D"],
#    ["no A", "no B", "no C", "no D"]]

Problem

What I want to do is deal with n sets, while the code I provide below works with exactly 4 sets. ``` def show_combinations @combos = [] ['A', 'no A'].each do |a| ['B', 'no B'].each do |b| ['C', 'no C'].each do |c| ['D', 'no D'].each do |d| @combos << [a, b, c, d] end end end end end ``` How can I refactor this following code to deal with the following scenario: Given I have an array of size y containing arrays of size n, I want to return all the combinations. It's important to note that only one item in each of the sub arrays can be in the results. (Such as "Completed Profile" can't also be in the results with "Not completed profile") Background: A user might have some tasks: for example, "Complete Profile" or "Set Up Email" or whatever. Those tasks can be represented like this: ``` @task_states = [["Completed Profile, NOT Completed Profile"], ["Set up Email", "NOT set up Email"]] ``` Then, passing @task_states into the method, the results should be this: ``` [ ["Completed Profile", "Set up Email"], ["Completed Profile", "NOT set up Email"], ["NOT Completed Profile", "Set up Email"], ["NOT Completed Profile", "NOT Set up Email"] ] ``` So an array of arrays representing all the combinations. Obviously "Completed Profile" can't also be in the same array as "NOT Completed Profile," etc. Thanks!

Original source