更有效的地图绘制方式在Ruby中减少?

时间:2014-04-09 23:51:57

标签: ruby map reduce

假设您有一个散列,其中键是字符串,值是Floats。您希望按每个键的子字符串对值进行分组,然后对每个组中的值求和。

基本上,你想要离开这个:

{ "aaaapattern1aaaa" => 213.2342, "pattern2aaaa" => 0.03, 
  "aaaaapattern3" => 12.1, "pattern1aaa" => 54.4544, 
  "aaaaapattern2" => 65.003 }

到此:

{"pattern1"=>267.6886, "pattern2"=>65.033, "pattern3"=>12.1}

这是我目前的做法:

data = {
  "aaaapattern1aaaa"=>213.2342, "pattern2aaaa"=>0.03, 
  "aaaaapattern3"=>12.1, "pattern1aaa"=>54.4544, 
  "aaaaapattern2"=>65.003
}

key_regexp = /pattern\d/

intermediate_results = data.map do |key, value| 
  { key.match(key_regexp)[0] => value } 
end

final_result = intermediate_results.reduce do |cumulative_hash, individual_hash| 
  cumulative_hash.merge(individual_hash) do |key, old_value, new_value| 
    old_value + new_value 
  end
end

你会如何改进?在制定理想方法时应考虑哪些因素?你的答案是否会根据哈希的大小而改变,如果是的话,怎么样?

3 个答案:

答案 0 :(得分:3)

这应该是非常简单的很多工作:

sums = Hash.new(0)

d.each do |key, value|
  if (m = key.match(/pattern\d/))
    sums[m[0]] += value
  end
end

sums
# => {"pattern1"=>267.6886, "pattern2"=>65.033, "pattern3"=>12.1}

这有利于忽略任何不匹配的东西。

此处Hash.new(0)创建一个默认值为0的哈希值。这是一个很好的模式,用于组合任意事物的总和。

答案 1 :(得分:0)

我想我会做类似下面的事情。我不能过多地谈论表现。

sums = Hash.new(0) #Initialize hash with 0 as default
data.each do |k,v|
  case k #switch on the key
  when /pattern1/ #do regex pattern checks
   sums[:pattern_1] += v
  when /pattern2/
   sums[:pattern_2] += v
  else
    #undefined pattern
  end
end

答案 2 :(得分:0)

如果你使用each_with_object,你可以使它相当紧凑。

假设datakey_regexp与您定义的相同:

data.each_with_object(Hash.new(0)) do |(k,v),r|
  r[k.match(key_regexp)[0]] += v
end