Использование
def merge_by(a,b, key)
(a+b).group_by { |h| h[key] }
.each_value.map { |arr| arr.inject(:merge) }
end
merge_by(
merge_by(customer_mapping, customer_with_products, :customer_order_id),
product_mapping,
:product_order_id
).select { |h| h[:product_id] }.map { |h| h.slice(:product_id, :customer_id) }
#=>[{:product_id=>"j", :customer_id=>"a"},
# {:product_id=>"k", :customer_id=>"b"},
# {:product_id=>"l", :customer_id=>"c"}]
Определенно не самое чистое решение, если ваши исходные массивы исходят из SQL-запросов, я думаю, что эти запросы можно изменить для правильной агрегации ваших данных.
merge_by(customer_mapping, customer_with_products, :customer_order_id)
# => [{:customer_id=>"a", :customer_order_id=>"g1", :product_order_id=>"a1"},
# {:customer_id=>"b", :customer_order_id=>"g2", :product_order_id=>"a2"},
# {:customer_id=>"c", :customer_order_id=>"g3", :product_order_id=>"a3"},
# {:customer_id=>"d", :customer_order_id=>"g4", :product_order_id=>"a4"},
# {:customer_id=>"e", :customer_order_id=>"g5", :product_order_id=>"a5"}]
Затем объедините его аналогично с вашим последним массивом и очистите результат, выбрав только те элементы, для которых было найдено :product_id
, нарезав нужные ключи.
В качестве альтернативы, гораздо более читаемое решение, в зависимости от размеров вашего массива, может быть медленнее.поскольку он продолжает перебирать хэши:
product_mapping.map do |hc|
b_match = customer_with_products.detect { |hb| hb[:product_order_id] == hc[:product_order_id] }
a_match = customer_mapping.detect { |ha| ha[:customer_order_id] == b_match[:customer_order_id] }
[hc, a_match, b_match].inject(:merge)
end.map { |h| h.slice(:product_id, :customer_id) }