【问题标题】:Add key value pair to Array of Hashes when unique Id's match当唯一 ID 匹配时,将键值对添加到哈希数组
【发布时间】:2015-06-24 19:41:15
【问题描述】:

我有两个哈希数组

sent_array = [{:sellersku=>"0421077128", :asin=>"B00ND80WKY"},
{:sellersku=>"0320248102", :asin=>"B00WTEF9FG"}, 
{:sellersku=>"0324823180", :asin=>"B00HXZLB4E"}]

active_array = [{:price=>39.99, :asin1=>"B00ND80WKY"}, 
{:price=>7.99, :asin1=>"B00YSN9QOG"}, 
{:price=>10, :asin1=>"B00HXZLB4E"}]

我想遍历sent_array,找到:asin中的值等于active_array中:asin1中的值的位置,然后将:price的键和值复制到sent_array。结果是这样的:

final_array = [{:sellersku=>"0421077128", :asin=>"B00ND80WKY", :price=>39.99},
{:sellersku=>"0320248102", :asin=>"B00WTEF9FG"}, 
{:sellersku=>"0324823180", :asin=>"B00HXZLB4E", :price=>10}]

我试过这个,但我得到一个 TypeError - 没有将 Symbol 隐式转换为 Integer (TypeError)

sent_array.each do |x|
 x.detect { |key, value| 
  if value == active_array[:asin1]
    x[:price] << active_array[:price]
  end
 }
end

【问题讨论】:

    标签: arrays ruby hash


    【解决方案1】:

    出于效率和可读性的原因,首先在active_array上构造一个查找哈希是有意义的:

    h = active_array.each_with_object({}) { |g,h| h[g[:asin1]] = g[:price] } 
      #=> {"B00ND80WKY"=>39.99, "B00YSN9QOG"=>7.99, "B00HXZLB4E"=>10}
    

    我们现在只需通过sent_array,更新哈希值:

    sent_array.each { |g| g[:price] = h[g[:asin]] if h.key?(g[:asin]) }
      #=> [{:sellersku=>"0421077128", :asin=>"B00ND80WKY", :price=>39.99},
      #    {:sellersku=>"0320248102", :asin=>"B00WTEF9FG"}, 
      #    {:sellersku=>"0324823180", :asin=>"B00HXZLB4E", :price=>10}] 
    

    从散列 (h) 中检索键值对当然比在散列数组中搜索键值对要快得多。

    【讨论】:

    • 谢谢卡里!像魅力一样工作..我花了一些时间来弄清楚each_with_object到底做了什么..如果我错了,请纠正我,但首先它会创建一个新的哈希,然后逐步通过active_array从以下值创建键: asin1 并将 :price 作为其值。
    • 是的,Enumerable#each_with_object 还做了一件事:它返回对象。因此,它节省了两个步骤:h={}; active_array.each { |g| ... }; h。该方法在 v1.9 中首次亮相。那是在我的时代之前——那时我还是个孩子——但有人告诉我,这里会使用 pre-1.9,Enumerable#reduce(又名inject)。 (顺便说一句 reduce 仍然有许多奇妙的用途)
    【解决方案2】:

    这可以解决问题。遍历您发送的数组并尝试在您的 active_array 中找到具有该 :asin 的记录。如果你找到东西,设定价格,你就完成了。

    我认为您的代码错误地使用了检测/查找。您想要从该方法中得到的是匹配的哈希,然后对其进行处理。你试图在检测中做所有事情。

    sent_array.each do |sent|
      item = active_array.find{ |i| i.has_value? sent[:asin] }
      sent[:price] = item[:price] if item
    end
    
     => [{:sellersku=>"0421077128", :asin=>"B00ND80WKY", :price=>39.99}, {:sellersku=>"0320248102", :asin=>"B00WTEF9FG"}, {:sellersku=>"0324823180", :asin=>"B00HXZLB4E", :price=>10}] 
    

    【讨论】:

      【解决方案3】:

      我假设sent_arrayactive_array 的第二个元素分别具有B00WTEF9FG asin 和asin1。 (看你的最终结果)

      现在:

      a = active_array.group_by{|a| a[:asin1]}
      b = sent_array.group_by{|a| a[:asin]}
      a.map { |k,v|
         v[0].merge(b[k][0])
      }
      
      #  => [{:price=>39.99, :asin1=>"B00ND80WKY", :sellersku=>"0421077128", :asin=>"B00ND80WKY"}, {:price=>7.99, :asin1=>"B00WTEF9FG", :sellersku=>"0320248102", :asin=>"B00WTEF9FG"}, {:price=>10, :asin1=>"B00HXZLB4E", :sellersku=>"0324823180", :asin=>"B00HXZLB4E"}] 
      

      为什么会出现 TypeError?

      你正在做active_array[:asin1]。记住active_array 本身就是一个数组。除非您对其进行迭代,否则您无法查找密钥。

      您的方法的另一个问题是,您使用的是Hash#detect

      find 是根据each 实现的。和each,当被调用时 Hash,以具有 2 个元素的数组形式返回键值对 每个。这就是find 返回数组的原因。

      source

      detect 也是如此。所以x.detect { |key, value| .. } 不会像你期望的那样工作。

      没有假设的解决方案

      a.map { |k,v|
         b[k] ? v[0].merge(b[k][0]) : v[0]
      }.compact
      # => [{:price=>39.99, :asin1=>"B00ND80WKY", :sellersku=>"0421077128", :asin=>"B00ND80WKY"}, {:price=>7.99, :asin1=>"B00YSN9QOG"}, {:price=>10, :asin1=>"B00HXZLB4E", :sellersku=>"0324823180", :asin=>"B00HXZLB4E"}] 
      

      这里因为asin1 =&gt; "B00ND80WKY"没有匹配,所以不能从其他hash中得到sellersku

      【讨论】:

      • @Jeff Price.. Shivam,好点。谢谢你。是的,我仍然在“Jeff Price”的解决方案中遇到 TypeError。但是您的解决方案也不起作用,因为 sent_array 是 active_array 的子集..还有其他想法吗?
      • @ToddT 那是因为您的输入不正确。我已经在答案的第一行提到了这一点。我在做一个假设。
      • @ToddT 我也更新了给定案例的解决方案。请检查
      • Shoot.. 这也不起作用.. 我正在尝试解决这个问题,但我迷路了.. 基本上 group_by 的结果与地图。它看起来像这样:B0039UTCYI"=>[{:price=>"79", :asin1=>"B0039UTCYI"}] 所以现在缺少的部分是 :sellersku
      猜你喜欢
      • 2015-05-20
      • 2012-03-13
      • 1970-01-01
      • 2018-04-21
      • 2021-11-19
      • 2018-08-22
      • 2011-02-15
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多