2014-11-08 106 views
0

我想计算我的统计数据的增量。我已经试过HashDiff宝石来比较哈希。如何计算两个哈希之间的增量?

a = {"Lima, Peru"=>"83", "Chicago, IL"=>"35"} 
b = {"Lima, Peru"=>"80", "Chicago, IL"=>"40", "Krakow, Poland" => '3'} 

CalculateDelta.new(A,B).execute

b = {"Lima, Peru"=>"-3", "Chicago, IL"=>"5", "Krakow, Poland" => '3'} 

甚至更​​好

b = {"Lima, Peru"=>["-", "3"], "Chicago, IL"=>["+", "5"], "Krakow, Poland" => ["+", '3']} 

我已经写这样的事情

class CalculateDeltas < Struct.new(:a, :b) 
    def calculate 
    aa = a.to_a 
    ba = b.to_a 
    c = aa + ba 
    c.group_by(&:first).map{|k,v| [k, v.map(&:last).inject(:+)]} 
    end 
end 

回答

2

像这样的东西?:

class CalculateDelta 
    attr_reader :source, :target 
    def initialize(source, target) 
    @source = source 
    @target = target 
    end 

    def execute 
    target.each_with_object({}) do |(k, v), result| 
     result[k] = if source[k] 
     source_value, v = source[k].to_i, v.to_i 
     source_value > v ? ['-', "#{source_value - v}"]: ['+', "#{v - source_value}"] 
     else 
     ['+', v] 
     end 
    end 
    end 
end 

a = {"Lima, Peru"=>"83", "Chicago, IL"=>"35"} 
b = {"Lima, Peru"=>"80", "Chicago, IL"=>"40", "Krakow, Poland" => '3'} 

puts CalculateDelta.new(a,b).execute 
#=> {"Lima, Peru"=>["-", "3"], "Chicago, IL"=>["+", "5"], "Krakow, Poland"=>["+", "3"]} 
+0

哦!你是_Surya_ .. :-)为什么没有名字..? :) – 2014-11-08 11:52:48

+0

为什么?发生了什么..帐户锁定..? ;) – 2014-11-08 11:53:45

+0

是啊o.O告诉过你,对。错误:) – Surya 2014-11-08 11:54:12

0

Hash.new().tap{|h| b.each{|k,v| h[k] = v.to_i}; a.each{|k,v| h[k] -= v.to_i}}

返回{"Lima, Peru"=>-3, "Chicago, IL"=>5, "Krakow, Poland"=>3}


编辑 为了使这个代码仅返回哈希使用字符串:

Hash.new().tap{|h| b.each{|k,v| h[k] = v.to_i}; a.each{|k,v| h[k] -= v.to_i}}. 
    tap{|h| h.each{|k,v| h[k] = h[k].to_s }} 

返回{"Lima, Peru"=>"-3", "Chicago, IL"=>"5", "Krakow, Poland"=>"3"}

+0

'Hash.new()。tap {| h | b.each {| K,V | h [k] = v.to_i}; a.each {| K,V | NameError:未定义的局部变量或方法'b'for main:Object'无论如何,这并不会产生所需的输出。值应该是string而不是fixnum。 – Surya 2014-11-08 11:50:22

+0

那么哈希'a'和'b'必须在使用它们的范围内......这就是你的错误告诉你的。为了使字符串脱离它:'.tap {| h | h.each {| K,V | h [k] = h [k] .to_s}}' – lSoleyl 2014-11-08 11:54:16

1

保持简单:

b.keys.each { |k| b[k] = (b[k].to_i-a[k].to_i).to_s if a.key?(k) } 
b #=> {"Lima, Peru"=>"-3", "Chicago, IL"=>"5", "Krakow, Poland" => "3"} 

注意,该规范是突变b

进一步简化是可能的,但我不会建议吧:

b.keys.each { |k| b[k] = (b[k].to_i-a[k].to_i).to_s } 
b 

我听到有人反对说a[k] = nil如果a没有关键k。这是真的,但是nil.to_i => 0。 :-)