从多个哈希数组构建一个新的哈希数组

时间:2018-11-21 17:57:32

标签: ruby-on-rails ruby

我有以下三个哈希数组。

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_with_products中选择与product_order_id匹配的customer_order_id,然后想到遍历customer_mapping但无法从第一步获得所需的输出。

我该如何实现?

5 个答案:

答案 0 :(得分:2)

使用

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) }

答案 1 :(得分:1)

在解决问题之后,解决方案如下:

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"}]

答案 2 :(得分:0)

其他选项,从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}]

答案 3 :(得分:0)

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"}]

此配方特别易于测试。 (非常简单,不需要调试。)

答案 4 :(得分:0)

我建议采取一个更长一些但更具可读性的解决方案,从现在开始的几个月中,您也会对它有所了解。使用全名作为哈希键,而不是将其隐藏在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