Вы хотите вычислить «произведение» двух списков, что на самом деле очень просто, поскольку Ruby имеет функцию product
специально для этого:
KEYS = %i[ shape color ]
def all_shape_colors(shapes, colors)
shapes.product(colors).map do |pair|
KEYS.zip(pair).to_h
end
end
zip
используется здесь для ввода двух записей в каждой паре.
На практике это выглядит так:
shapes = %w[ square circle triagle ]
colors = %w[ red blue ]
all_shape_colors(shapes, colors)
# => [{:shape=>"square", :color=>"red"}, {:shape=>"square", :color=>"blue"}, {:shape=>"circle", :color=>"red"}, {:shape=>"circle", :color=>"blue"}, {:shape=>"triagle", :color=>"red"}, {:shape=>"triagle", :color=>"blue"}]
Обратите внимание на использование %w[ x y ]
вместо [ "x", "y" ]
как способ выражения того же массива с более минимальным синтаксисом. %i[ ... ]
то же самое, но возвращает массив символов вместо строк.
На самом деле вы можете go еще один здесь и создать очень обобщенный c метод, который делает эту комбинацию для вас на произвольном числе. вещей:
def hash_product(**things)
keys = things.keys
things.values.inject do |s, options|
# Compute product and flatten, necessary for chains > length 2
s.product(options).map(&:flatten)
end.map do |set|
keys.zip(set).to_h
end
end
Где вы сейчас используете это так:
hash_product(shape: shapes, color: colors)
Это означает, что нет необходимости в фиксированном наборе ключей. Все будет работать:
hash_product(hair: %w[ red blue green ], hat: %w[ white black yellow ], shoes: %w[ orange brown tan])
# => [{:hair=>"red", :hat=>"white", :shoes=>"orange"}, {:hair=>"red", :hat=>"white", :shoes=>"brown"}, ... ]