2013-05-09 80 views
1

我有一个散列数组,其中包含特定重复键值的散列。具有多个键/值的合并散列

combined_keywords = new_array_of_hashes.each_with_object(Hash.new(0)){|oh, newh| 
     newh[oh[:keyword]] += oh[:total_value].to_f 
    } 

这将创建哈希看起来像这样的数组:

{ :ACTUAL_KEYWORD => ACTUAL_TOTAL_VALUE } 

我是新来的Ruby和我不太了解这背后的魔力。我有一个额外的关键和价值巩固,现在我迷路了。这个问题的根源是我不明白的整合是如何在这条线上发生:newh[oh[:keyword]] += oh[:total_value].to_f

我想这没有运气:

combined_keywords = new_array_of_hashes.each_with_object(Hash.new(0)){|oh, newh| 
      newh[oh[:keyword]] += oh[:total_value].to_f 
      newh[oh[:keyword]] += oh[:revenue_per_transaction].to_f 
     } 

我真的只需要consildated散列每个相似的阵列于:

{ :keyword => "ACTUAL_KEYWORD", :total_value => ACTUAL_TOTAL_VALUE, :revenue_per_transaction => ACTUAL_REVENUE } 

编辑:

输入

new_array_of_hashes = [ 
    { keyword: 'foo', total_value: 1, revenue_per_transaction: 5 }, 
    { keyword: 'bar', total_value: 2, revenue_per_transaction: 4 }, 
    { keyword: 'bar', total_value: 4, revenue_per_transaction: 4 }, 
    { keyword: 'foo', total_value: 3, revenue_per_transaction: 5 }, 
] 

所需的输出

combined_keywords = [ 
    { keyword: 'foo', total_value: 4, revenue_per_transaction: 10 }, 
    { keyword: 'bar', total_value: 6, revenue_per_transaction: 8 }, 
] 
+0

你能给的4所预计投入的样本和你想要的输出是什么样的循环? – 2013-05-10 01:10:31

+0

我在我的期望的输出中添加了 – mnort9 2013-05-10 20:43:18

回答

3

比方说,你有:

new_array_of_hashes = [ 
    { keyword: 'foo', total_value: 1 }, 
    { keyword: 'bar', total_value: 2 }, 
    { keyword: 'bar', total_value: 4 }, 
    { keyword: 'foo', total_value: 3 }, 
] 

现在,我们将通过您的代码步:

combined_keywords = new_array_of_hashes.each_with_object(Hash.new(0)){|oh, newh| 
    newh[oh[:keyword]] += oh[:total_value].to_f 
} 

这将循环遍历每个哈希阵列。我们还建立一个新的哈希返回0如果我们访问的密钥不存在:

# Pass 1 
oh = { keyword: 'foo', total_value: 1 } 
newh = {} 
newh[ oh[:keyword] ] #=> newh['foo'] This key doesn't exist and returns 0 
oh[:total_value].to_f #=> 1.to_f => 1.0 
newh[oh[:keyword]] += oh[:total_value].to_f 
#=> newh['foo'] = newh['foo'] + oh[:total_value].to_f 
#=> newh['foo'] = 0 + 1.0 

# Pass 2 
oh = { keyword: 'bar', total_value: 2 } 
newh = { 'foo' => 1.0 } 
newh[ oh[:keyword] ] #=> newh['bar'] This key doesn't exist and returns 0 
oh[:total_value].to_f #=> 2.to_f => 2.0 
newh[oh[:keyword]] += oh[:total_value].to_f 
#=> newh['bar'] = newh['bar'] + oh[:total_value].to_f 
#=> newh['bar'] = 0 + 2.0 

现在,因为我们有我们的东西访问正常接下来的两个迭代键:

# Pass 3 
oh = { keyword: 'bar', total_value: 4 } 
newh = { 'foo' => 1.0, 'bar' => 2.0 } 
newh[ oh[:keyword] ] #=> newh['bar'] This key now exists and returns 2.0 
oh[:total_value].to_f #=> 4.to_f => 4.0 
newh[oh[:keyword]] += oh[:total_value].to_f 
#=> newh['bar'] = newh['bar'] + oh[:total_value].to_f 
#=> newh['bar'] = 2.0 + 4.0 

# Pass 4 
oh = { keyword: 'foo', total_value: 3 } 
newh = { 'foo' => 1.0, 'bar' => 6.0 } 
newh[ oh[:keyword] ] #=> newh['foo'] This key now exists and returns 1.0 
oh[:total_value].to_f #=> 3.to_f => 3.0 
newh[oh[:keyword]] += oh[:total_value].to_f 
#=> newh['foo'] = newh['foo'] + oh[:total_value].to_f 
#=> newh['foo'] = 1.0 + 3.0 

块返回时将返回newh;这是each_with_object的工作原理。

正如你所看到的,什么是返回的形式为哈希:

{ 'foo' => 4.0, 'bar' => 6.0 } 

因此,这是一个混合阵列,其中新的密钥存储:keyword对象,而该值的总和。

根据新的哈希表上

{ 
    keyword: "ACTUAL_KEYWORD", 
    total_value: ACTUAL_TOTAL_VALUE, 
    revenue_per_transaction: ACTUAL_REVENUE 
} 

这种格式将没有多大意义。由于哈希只有键:值对。您可能需要有一个散列哈希,或者遍历循环两次。一次为:total_value,一次为:revenue_per_transaction。这将取决于你希望你的最终目标是什么。

编辑:

根据您的新的预期的输入和输出,你可以使用:

sum_keys = [:total_value, :revenue_per_transaction] 
new_array_of_hashes.group_by{ |h| h[:keyword] } 
        .map{ |keyword, related| 
        tmp = {keyword: keyword} 
        tmp.merge! Hash[sum_keys.zip Array.new(sum_keys.size, 0)] 
        related.reduce(tmp){ |summed, h| 
         sum_keys.each{ |key| summed[key] += h[key] } 
         summed 
        } 
        } 

#=> [ 
# { keyword: 'foo', total_value: 4, revenue_per_transaction: 10 }, 
# { keyword: 'bar', total_value: 6, revenue_per_transaction: 8 }, 
#] 

这是一个有点乱。我可能会重构什么map调用正在做自己的帮手方法。我提供reduce的起始值的原因是因为否则它会改变new_array_of_hashes的原始散列值。

+0

对'each_with_object'的好的点对点解释。 – 2013-05-10 08:08:59

0

鉴于

foos = [ { :key => 'Foo', :value => 1, :revenue => 2 }, 
     { :key => 'Foo', :value => 4, :revenue => 8 } ] 

你可以做到这一点

foos.each_with_object(Hash.new(0)) do |foo_hash, new_hash| 
    new_hash[:keyword] = foo_hash[:key] 
    new_hash[:total_value] += foo_hash[:value] 
    new_hash[:total_revenue] += foo_hash[:revenue] 
end 

所以each_with_object允许你传递的参数可枚举的。每个块。在这种情况下,你传递Hash.new(0)。 0参数是一种设置默认散列值的方法,因此您不必在循环中将值明确归零,并且可以正确地递增。 +=只是简写。所以a += b相当于a = a + b

关于循环的笨拙的事情是它设置每次通过new_hash [:关键字]值。你可以使用if new_hash[:keyword] == 0(因为它初始为零),但这只是一个绷带。问题在于原始的哈希结构。如果:键等于'Foo',那么'Foo'是多余的。如果它不总是'Foo',那么这个循环不是很有用。

以上产量

{ :keyword => 'Foo', :total_value => 5, :total_revenue => 10 } 
相关问题