построить новый массив хешей из нескольких массивов хешей - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть следующие три массива хэшей.

customer_mapping = [
      {:customer_id=>"a", :customer_order_id=>"g1"},
      {:customer_id=>"b", :customer_order_id=>"g2"},
      {:customer_id=>"c", :customer_order_id=>"g3"},
      {:customer_id=>"d", :customer_order_id=>"g4"},
      {:customer_id=>"e", :customer_order_id=>"g5"}
    ]

customer_with_products = [
      {:customer_order_id=>"g1", :product_order_id=>"a1"},
      {:customer_order_id=>"g2", :product_order_id=>"a2"},
      {:customer_order_id=>"g3", :product_order_id=>"a3"},
      {:customer_order_id=>"g4", :product_order_id=>"a4"},
      {:customer_order_id=>"g5", :product_order_id=>"a5"}
    ]

product_mapping = [
    {:product_id=>"j", :product_order_id=>"a1"},
    {:product_id=>"k", :product_order_id=>"a2"},
    {:product_id=>"l", :product_order_id=>"a3"}
  ]

Мне нужен новый хэш только с customer_id и product_id

{:product_id=>"j", :customer_id=>"a"},
{:product_id=>"k", :customer_id=>"b"},
{:product_id=>"l", :customer_id=>"c"}

Я попытался перебрать product_mapping и выбратьcustomer_order_id, который соответствует product_order_id в customer_with_products, а затем подумал о циклическом переходе по customer_mapping, но не смог получить желаемый результат с первого шага.

Как мне этого добиться?

Ответы [ 5 ]

0 голосов
/ 22 ноября 2018

Я бы порекомендовал взять более длинное, но более читаемое решение, которое вы также поймете через несколько месяцев, посмотрев на него.Используйте полные имена для ключей хеша вместо того, чтобы прятать их за k, v для более сложных поисков (возможно, это просто мои личные предпочтения).

Я бы предложил что-то вроде:

result = product_mapping.map do |mapping|
  customer_id = customer_mapping.find do |hash|
    hash[:customer_order_id] == customer_with_products.find do |hash|
      hash[:product_order_id] == mapping[:product_order_id]
    end[:customer_order_id]
  end[:customer_id]

  { product_id: mapping[:product_id], customer_id: customer_id }
end
0 голосов
/ 22 ноября 2018
cust_order_id_to_cust_id =
  customer_mapping.each_with_object({}) do |g,h|
    h[g[:customer_order_id]] = g[:customer_id]
  end
  #=> {"g1"=>"a", "g2"=>"b", "g3"=>"c", "g4"=>"d", "g5"=>"e"}

prod_order_id_to_cust_order_id =
  customer_with_products.each_with_object({}) do |g,h|
    h[g[:product_order_id]] = g[:customer_order_id]
  end
  #=> {"a1"=>"g1", "a2"=>"g2", "a3"=>"g3", "a4"=>"g4", "a5"=>"g5"}

product_mapping.map do |h|
  { product_id: h[:product_id], customer_id: 
    cust_order_id_to_cust_id[prod_order_id_to_cust_order_id[h[:product_order_id]]] }
end
  #=> [{:product_id=>"j", :customer_id=>"a"},
  #    {:product_id=>"k", :customer_id=>"b"},
  #    {:product_id=>"l", :customer_id=>"c"}]

Этот состав особенно легко проверить.(Это так просто, что отладка не нужна).

0 голосов
/ 21 ноября 2018

После решения проблемы решение будет следующим:

result_hash_array = product_mapping.map do |product_mapping_entry|
        customer_receipt = customer_with_products.find do |customer_with_products_entry|
            product_mapping_entry[:product_order_id] == customer_with_products_entry[:product_order_id]
        end
        customer_id = customer_mapping.find do |customer_mapping_entry|
            customer_receipt[:customer_order_id] == customer_mapping_entry[:customer_order_id]
        end[:customer_id]
        {product_id: product_mapping_entry[:product_id], customer_id: customer_id}
end

Вывод

results_hash_array => [{:product_id=>"j", :customer_id=>"a"},
                       {:product_id=>"k", :customer_id=>"b"},
                       {:product_id=>"l", :customer_id=>"c"}]
0 голосов
/ 21 ноября 2018

Другой вариант, начиная с customer_mapping, один вкладыш (но довольно широкий):

customer_mapping.map { |e| {customer_id: e[:customer_id], product_id: (product_mapping.detect { |k| k[:product_order_id] == (customer_with_products.detect{ |h| h[:customer_order_id] == e[:customer_order_id] } || {} )[:product_order_id] } || {} )[:product_id]  } }

#=> [{:customer_id=>"a", :product_id=>"j"},
#    {:customer_id=>"b", :product_id=>"k"},
#    {:customer_id=>"c", :product_id=>"l"},
#    {:customer_id=>"d", :product_id=>nil},
#    {:customer_id=>"e", :product_id=>nil}]
0 голосов
/ 21 ноября 2018

Использование

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) }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...