coconup coconup - 24 days ago 9
Ruby Question

Ruby: multidimensional array to one-dimensional rows

In Ruby, how do I go from this:

[
1,
["green", "blue", "black"],
[ ["1", "2"], ["3"], ["4", "5"] ]
]


to this?

[
[1, "green", "1"],
[1, "green", "2"],
[1, "blue", "3"],
[1, "black", "4"],
[1, "black", "5"],
]


I tried .zip but with no luck. Any help is greatly appreciated, and of course I'm looking for a performant solution.

Answer Source

I needed a more generic and flexible solution as compared to the ones proposed (my bad, I should have been more clear about the requirements), so I came up with the following:

class Array
  def transpose_rows
    arys = self.select{|el| el.is_a?(Array)}
    if arys.size == 0
      [self]
    else 
      result = []
      (arys.map(&:size).max || 1).times.map{ |i|
        self.map { |r| 
          r.is_a?(Array) ? r[i] : r
        }.transpose_rows.map{|r| result << r}
      }
      result
    end
  end
end

The initial spec is that every element in the array is either a value or another array of varying depth. Each subarray "explodes" the values of the subarrays of depth-1 into an arbitrary number of "sub-values". The result should be a set of rows listing all combinations deriving from the original array.

The other solutions proposed do work for the original array I posted, which was just an example, while this one works for more complex scenarios such as the following:

[
  2, 
  [3,4,5], 
  6, 
  [7,8,9], 
  [ [11,22], [33], [44,55] ], 
  [0, 1, 2],
  [ [66], [77], [nil,99] ],
  4
].transpose_rows

# => [
#   [2, 3, 6, 7, 11, 0, 66, 4], 
#   [2, 3, 6, 7, 22, 0, nil, 4], 
#   [2, 4, 6, 8, 33, 1, 77, 4], 
#   [2, 5, 6, 9, 44, 2, nil, 4], 
#   [2, 5, 6, 9, 55, 2, 99, 4]
# ]