0

I have an array like the following:

[["red", "green", "blue"], ["small", "large", "medium"], ["loose", "tight"]]

I need to pull all of these arrays out of the parent, into separate arrays, like this:

["red", "green", "blue"] ["small", "large", "medium"] ["loose", "tight"]

The program won't always know how many child arrays will be in the parent array, because they are dynamically created.

The end goal is to take the first array (red, green, blue, etc...) and call .product on it, passing in all the following arrays, individually, so I end up with the following:

"red small loose", "red small right", "red large loose", etc..

5
  • 1
    Is this possible, yes. The question becomes, how do you want to store each array? What are you doing with this data that it needs to be separated out? Commented Sep 4, 2014 at 15:03
  • I'd like the child arrays to stay as arrays, but not be in a parent. I'm trying to call product on the first array and pass in the rest of the arrays individually. Commented Sep 4, 2014 at 15:04
  • @jmcharnes Perhaps you could edit your question to clearly explain that goal in detail. (It's definitely possible to achieve, and not particularly hard either.) Commented Sep 4, 2014 at 15:07
  • Give some sample input (you already have that), and the output you would like after applying your function. Commented Sep 4, 2014 at 15:08
  • Sorry about that guys, I've updated the question to show my end goal. Commented Sep 4, 2014 at 15:11

3 Answers 3

4

This would work:

arrays = [["red", "green", "blue"], ["small", "large", "medium"], ["loose", "tight"]]

first, *others = arrays
first.product(*others).map { |s| s.join(' ') }
#=> ["red small loose", "red small tight", "red large loose", "red large tight", "red medium loose", "red medium tight", "green small loose", "green small tight", "green large loose", "green large tight", "green medium loose", "green medium tight", "blue small loose", "blue small tight", "blue large loose", "blue large tight", "blue medium loose", "blue medium tight"]

Or without temporary variables:

arrays[0].product(*arrays[1..-1]).map { |s| s.join(' ') }

Note that the argument for product is prefixed with a *. This is called the splat operator - it turns an array into an argument list.

Sign up to request clarification or add additional context in comments.

Comments

0

I think you can do this:

2.1.0 :001 > parent_array = [["red", "green", "blue"], ["small", "large", "medium"], ["loose", "tight"]]
 => [["red", "green", "blue"], ["small", "large", "medium"], ["loose", "tight"]] 
2.1.0 :002 > first_array = parent_array.shift
 => ["red", "green", "blue"] 
2.1.0 :003 > first_array
 => ["red", "green", "blue"] 
2.1.0 :004 > parent_array
 => [["small", "large", "medium"], ["loose", "tight"]] 

# Use the splat operator (*)
2.1.0 :006 > product = first_array.product(*parent_array)
 => [["red", "small", "loose"], ["red", "small", "tight"], ["red", "large", "loose"], ["red", "large", "tight"], ["red", "medium", "loose"], ["red", "medium", "tight"], ["green", "small", "loose"], ["green", "small", "tight"], ["green", "large", "loose"], ["green", "large", "tight"], ["green", "medium", "loose"], ["green", "medium", "tight"], ["blue", "small", "loose"], ["blue", "small", "tight"], ["blue", "large", "loose"], ["blue", "large", "tight"], ["blue", "medium", "loose"], ["blue", "medium", "tight"]] 
2.1.0 :007 > result = product.map {|array| array.join(' ') }
 => ["red small loose", "red small tight", "red large loose", "red large tight", "red medium loose", "red medium tight", "green small loose", "green small tight", "green large loose", "green large tight", "green medium loose", "green medium tight", "blue small loose", "blue small tight", "blue large loose", "blue large tight", "blue medium loose", "blue medium tight"] 

Comments

0

This is one of those problems for which there is really only one good solution, here the one given by @Stefan. Still, it is fun, and possibly instructive, to try to dream up other ways. Here's a recursive approach:

arr = [["red",   "green", "blue"],
       ["small", "large", "medium"],
       ["loose", "tight"]]

def combo(arr)
  return arr.first.product(arr.last) if arr.size == 2
  combo(arr[1..-1]).flat_map { |c| arr.first.map { |f| [f, *c] } }
end

combo(arr)
  #=> [["red",   "small",  "loose"], ["green", "small",  "loose"],
  #    ["blue",  "small",  "loose"], ["red",   "small",  "tight"],
  #    ["green", "small",  "tight"], ["blue",  "small",  "tight"],
  #    ["red",   "large",  "loose"], ["green", "large",  "loose"],
  #    ...
  #    ["green", "medium", "tight"], ["blue",  "medium", "tight"]]

I have assumed that the order of the elements in the array returned is not important.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.