合并哈希数组中的重复项

时间:2014-06-15 19:49:39

标签: ruby

我在ruby中有一系列哈希:

[
  {name: 'one', tags: 'xxx'},
  {name: 'two', tags: 'yyy'},
  {name: 'one', tags: 'zzz'},
]

我正在寻找任何干净的红宝石解决方案,这将使它能够简单地合并该数组中的所有重复项(通过合并我的意思是合并tags参数),所以上面的例子将转换为:

[
  {name: 'one', tags: 'xxx, zzz'},
  {name: 'two', tags: 'yyy'},
]

我可以迭代每个数组元素,检查是否有重复,将其与原始条目合并并删除副本但我觉得可以有更好的解决方案,并且这种方法有一些警告我不知道。谢谢你的任何线索。

2 个答案:

答案 0 :(得分:6)

我可以认为是

arr = [
  {name: 'one', tags: 'xxx'},
  {name: 'two', tags: 'yyy'},
  {name: 'one', tags: 'zzz'},
]

merged_array_hash = arr.group_by { |h1| h1[:name] }.map do |k,v|
  { :name => k, :tags =>  v.map { |h2| h2[:tags] }.join(" ,") } 
end

merged_array_hash
# => [{:name=>"one", :tags=>"xxx ,zzz"}, {:name=>"two", :tags=>"yyy"}]

答案 1 :(得分:3)

这是一种利用Hash#update(又名Hash.merge!)形式的方法,它采用一个块来确定两个哈希值中存在的每个键的合并值被合并。

<强>代码

def combine(a)
  a.each_with_object({}) { |g,h| h.update({ g[:name]=>g }) { |k,hv,gv|
           { name: k, tags: hv[:tags]+", "+gv[:tags] } } }.values  
end

示例

a = [{name: 'one', tags: 'uuu'},
     {name: 'two', tags: 'vvv'},
     {name: 'one', tags: 'www'},
     {name: 'six', tags: 'xxx'},
     {name: 'one', tags: 'yyy'},
     {name: 'two', tags: 'zzz'}]

combine(a)
  #=> [{:name=>"one", :tags=>"uuu, www, yyy"},
  #    {:name=>"two", :tags=>"vvv, zzz"     },
  #    {:name=>"six", :tags=>"xxx"          }]

<强>解释

假设

a = [{name: 'one', tags: 'uuu'},
     {name: 'two', tags: 'vvv'},
     {name: 'one', tags: 'www'}]

b = a.each_with_object({})
  #=> #<Enumerator: [{:name=>"one", :tags=>"uuu"},
  #                  {:name=>"two", :tags=>"vvv"},
  #                  {:name=>"one", :tags=>"www"}]:each_with_object({})>

我们可以将枚举器b转换为数组,以查看它将传递到其块中的值:

b.to_a
  #=> [[{:name=>"one", :tags=>"uuu"}, {}],
  #    [{:name=>"two", :tags=>"vvv"}, {}],
  #    [{:name=>"one", :tags=>"www"}, {}]]

传递给块并分配给块变量的第一个值是:

g,h = [{:name=>"one", :tags=>"uuu"}, {}]
g #=> {:name=>"one", :tags=>"uuu"}
h #=> {}

现在执行第一个合并操作(返回合并的h):

h.update({ g[:name] => g })
  #=> h.update({ "one" => {:name=>"one", :tags=>"uuu"} })
  #=> {"one"=>{:name=>"one", :tags=>"uuu"}}

h没有密钥"one",因此update&#39}的区块不会被调用。

接下来,枚举器b将以下内容传递给块:

g #=> {:name=>"two", :tags=>"vvv"}
h #=> {"one"=>{:name=>"one", :tags=>"uuu"}}

所以我们执行:

h.update({ g[:name] => g })
  #=> h.update({ "two"=>{:name=>"two", :tags=>"vvv"})
  #=> {"one"=>{:name=>"one", :tags=>"uuu"},
  #    "two"=>{:name=>"two", :tags=>"vvv"}}

同样,h没有密钥"two",因此不使用该块。

最后,each_with_object将最后一个元组传递到块中:

g #=> {:name=>"one", :tags=>"www"}
h #=> {"one"=>{:name=>"one", :tags=>"uuu"},
  #    "two"=>{:name=>"two", :tags=>"vvv"}}

我们执行:

h.update({ g[:name] => g })
  #=> h.update({ "one"=>{:name=>"one", :tags=>"www"})

h具有键"one"的键/值对:

"one"=>{:name=>"one", :tags=>"uuu"}
因此,执行

update块以确定合并值。以下值将传递给该块的变量:

k #=> "one"
hv #=> {:name=>"one", :tags=>"uuu"} <h's value for "one">
gv #=> {:name=>"one", :tags=>"www"} <g's value for "one">

并且块计算创建此哈希值(作为键的合并值&#34;一个&#34;):

{ name: k, tags: hv[:tags]+", "+gv[:tags] }
  #=> { name: "one", tags: "uuu" + ", " + "www" }
  #=> { name: "one", tags: "uuu, www" }

所以现在合并的哈希变为:

h #=> {"one"=>{:name=>"one", :tags=>"uuu, www"},
  #    "two"=>{:name=>"two", :tags=>"vvv"     }}

剩下的就是提取值:

h.values  
  #=> [{:name=>"one", :tags=>"uuu, www"}, {:name=>"two", :tags=>"vvv"}]