def extract_values_ordered_by_index(hash)
vals = hash.values.map(&:dup)
finish = [[]] * vals.size
loop.with_object([]) do |_,a|
break a if vals == finish
vals.each { |v| a << v.shift unless v.empty? }
end
end
doit({ a: [1, 2, 3], b: [4, 5], c: [6, 7, 8, 9], d:[] })
#=> [1, 4, 6, 2, 5, 7, 3, 8, 9]
doit({i: ['A'], ii: ['B', 'C', 'D'], iii: ['E'], iv: ['F', 'G']})
#=> ["A", "B", "E", "F", "C", "G", "D"]
I first extract the hash's values to an array vals, removing any empty arrays in the process.
I then build an array a until vals is empty, at which time I break the loop, returning a.
At each iteration I shift the first element of each element of vals (an array, guaranteed to be non-empty) and append the shifted element of a, then remove all (now-empty) elements (arrays) of vals.
I do it this way in part to avoid using Array#compact, which I regard as an ugly--though admittedly useful--method.
If, however, compact is to be used, one could write
def extract_values_ordered_by_index(hash)
vals = hash.values
vals.map { |a| Array.new(vals.max_by(&:size).size) { |i| a[i] } }
.transpose
.flatten
.compact
end