如何在保持值组合的同时合并数组的重复元素?

时间:2015-10-11 02:58:10

标签: ruby

我有这样的事情:

prods = [{"1050" => {"key" => "value", "key2" => "value2"}},
         {"1050" => {"key" => "value", "key2" => "value2"}},
         {"6650" => {"key" => "value", "key2" => "value2"}},
         {"6650" => {"key" => "value", "key2" => "value2"}}]

我想合并重复项,但保留像这样的键值对

prods = [{"1050" => [{"key" => "value", "key2" => "value2"}, 
                     {"key" => "value", "key2" => "value2"}}],
         {"6650" => [{"key" => "value", "key2" => "value2"},
                     {"key" => "value", "key2" => "value2"}}]
        ]

这可能吗?

3 个答案:

答案 0 :(得分:1)

这是许多人可以做到的一种方式。

<强>代码

def combine(prods)
  prods.map(&:flatten)
       .each_with_object(Hash.new {|h,k| h[k]=[]}) { |(k,v),h| h[k] << v }
       .map { |k,v| { k=>v } }
end

<强>实施例

您的prods的价值:

combine(prods)   
  #=> [{"1050"=>[{"key"=>"value", "key2"=>"value2"},
  #              {"key"=>"value", "key2"=>"value2"}]},
  #    {"6650"=>[{"key"=>"value", "key2"=>"value2"},
  #    {"key"=>"value", "key2"=>"value2"}]}]

现在让我们重新定义prods:

prods = [{"1050" => {"keya" => "value1", "keyb" => "value1"}},
         {"1050" => {"keya" => "value2", "keyb" => "value2"}},
         {"6650" => {"keya" => "value3", "keyb" => "value3"}},
         {"6650" => {"keya" => "value4", "keyb" => "value4"}}]
combine(prods)   
  #=> [{"1050"=>[{"keya"=>"value1", "keyb"=>"value1"},
  #              {"keya"=>"value2", "keyb"=>"value2"}]},
  #    {"6650"=>[{"keya"=>"value3", "keyb"=>"value3"},
 #               {"keya"=>"value4", "keyb"=>"value4"}]}] 

<强>解释

以下是步骤:

a = prods.map(&:flatten)
  #=> [["1050", {"key"=>"value", "key2"=>"value2"}],
  #    ["1050", {"key"=>"value", "key2"=>"value2"}],
  #    ["6650", {"key"=>"value", "key2"=>"value2"}],
  #    ["6650", {"key"=>"value", "key2"=>"value2"}]] 

h = a.each_with_object(Hash.new {|h,k| h[k]=[]}) { |(k,v),h| h[k] << v }
  #=> {"1050"=>[{"key"=>"value", "key2"=>"value2"},
  #             {"key"=>"value", "key2"=>"value2"}],
  #    "6650"=>[{"key"=>"value", "key2"=>"value2"},
  #             {"key"=>"value", "key2"=>"value2"}]} 

最后,

h.map { |k,v| { k=>v } }

产生上面显示的结果。

在计算h Enumerable#each_with_object中,对象是块变量h的值。最初,h是一个空哈希,定义如下:

Hash.new {|h,k| h[k]=[]}

该块给出了哈希的默认值。这表示如果h是散列并且k是要添加到散列的键,则它的默认值是空数组。传递给a块的each_with_object的第一个值是:

["1050", {"key"=>"value", "key2"=>"value2"}]

因此,块变量分配如下:

(k,v),h = [["1050", {"key"=>"value", "key2"=>"value2"}], {}]
  #=> [["1050", {"key"=>"value", "key2"=>"value2"}], {}] 
k #=> "1050" 
v #=> {"key"=>"value", "key2"=>"value2"} 
h #=> {} 

并且块计算是:

h[k] << v

是:

h["1050"] << {"key"=>"value", "key2"=>"value2"}

由于h没有密钥"1050"h["1050"]首先被分配了默认值,即空哈希,所以我们有:

(h["1050"] = []) << {"key"=>"value", "key2"=>"value2"}

哈希h现在是:

h #=> { "1050"=>[{"key"=>"value", "key2"=>"value2"}] }

a的下一个值传递给块,导致块变量更新如下:

(k,v),h = [["1050", {"key"=>"value", "key2"=>"value2"}],
           { "1050"=>[{"key"=>"value", "key2"=>"value2"}] }]
k #=> "1050" 
v #=> {"key"=>"value", "key2"=>"value2"} 
h #=> {"1050"=>[{"key"=>"value", "key2"=>"value2"}]} 

因此,块计算是:

h[k] << v
  # h["1050"] << {"key"=>"value", "key2"=>"value2"}

由于h现在具有键"1050"(其值为数组),因此不使用默认值,并且哈希h变为

h #=> {"1050"=>[{"key"=>"value", "key2"=>"value2"},
  #             {"key"=>"value", "key2"=>"value2"}]} 

其余的计算也是类似的。

答案 1 :(得分:0)

h = Hash.new {[]}   # this creates a new array when a key doesn't exist
prods.each do |prod|
  prod.each{ |key,val| h[key] = h[key] << val }
end
puts h

答案 2 :(得分:0)

以下是我提出的解决方案:

results =
prods.each_with_object(Hash.new([])) do |hash, results|
  key    = hash.keys.first
  values = hash.values

  results[key] += values
end

results = results.map { |k, v| Hash[k, v] }

在这个解决方案中,我只使用带有默认值的哈希来处理重复项,然后转换为所需的输出格式。

替代解决方案:

def find_hash(haystack, needle)
  haystack.index { |hay| hay.keys.first == needle }
end

results =
prods.each_with_object(Array.new) do |hash, results|
  key    = hash.keys.first
  values = hash.values

  idx = find_hash(results, key)

  if idx
    results[idx][key] += values
  else
    results << Hash[key, values]
  end
end

在这里,我尝试查找是否已存在具有指定键的哈希,然后附加到它,否则创建一个新哈希并将其添加到数组中。