2014-11-08 4 views
0

Я бы хотел рассчитать дельта для моей статистики. Я уже пробовал HashDiff драгоценный камень для сравнения хешей.Как рассчитать дельта между двумя хэшами?

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

CalculateDelta.new (а, б) .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_ .. :-) Почему нет имени ..? :) –

+0

Почему? Что случилось .. Блокировка учетной записи ..? ;) –

+0

да о.О сказал вам, правильно. blunder :) – Surya

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}


EDIT Для того, чтобы этот код возврата только строки в использовании хэш:

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 {| к, v | h [k] = v.to_i}; a.each {| к, v | h [k] - = v.to_i}} # => NameError: неопределенная локальная переменная или метод 'b' для main: Object' Это не дает желаемого результата в любом случае. Значения должны быть строковыми, а не fixnum. – Surya

+0

Ну, хэши 'a' и' b' должны иметь возможность использовать их ... Это то, о чем ваша ошибка говорит вам. Чтобы из него вывести строки: '.tap {| h | h.each {| к, v | h [k] = h [k] .to_s}} ' – lSoleyl

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. :-)

Смежные вопросы