2017-06-13 68 views
4

我想從具有相同鍵和平均值的多個哈希數組中創建一個數組/散列。我的數組:從數組中添加哈希

[{:amount=>897500, :gross_amount=>897500, :tax=>147500, :hotel_fees=>0, :base_fare=>750000, :currency=>"INR"}, {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"}] 

現在我想回到這樣的事情:

{:amount=>952000, :gross_amount=>952000, :tax=>152000, :hotel_fees=>0, :base_fare=>800000, :currency=>"INR"} 

其中值是值從同一個密鑰每個哈希的平均值。

有沒有簡單的方法來做到這一點。我嘗試過使用合併,但貨幣變爲0。

我嘗試:

p[0].merge(p[1]){|k,v1,v2| (v1+v2)/2 unless v1 && v2 == "INR"} 

編輯:

其實我的問題並沒有到此結束,所以獲得平均後,我需要插入另一哈希內的值。 所以我用這樣的事情:

 price_array = offer_values.map do |v| 
      v.inject do |k, v| 
      k.merge!(price: k[:price].merge(v[:price]){|_, a, b| [a, b].flatten }) 
      end 
     end 
     price_array.map do |o| 
      o[:price] = {}.tap{ |h| o[:price].each {|k, list| h[k] = list.all?{|e| [Fixnum, NilClass].include? e.class} ? list.map(&:to_i).sum/list.size : list.compact.first ; h } } 
     end 

哪裏offer_array是一個在單獨的哈希我的原單/第一個數組。這我已經嘗試過2和3次哈希,它正在工作。

如果你們有任何改善代碼的建議,它是開放的。

+1

_ 「我嘗試過使用合併」 - 你能否顯示你的嘗試? – Stefan

+0

合併返回這個'{:amount => 952000,:gross_amount => 952000,:tax => 152000,:hotel_fees => 0,:base_fare => 800000,:currency => nil}' – Ravi

+0

我不能貨幣零。 – Ravi

回答

1

對於數組兩個散列你可以使用injectmerge檢查是否爲雙方currency鍵的值是Fixnum對象類,如果沒有,那麼採取貨幣"INR"的值在第一哈希並使用它:

array = [ 
    {:amount=>897500, :gross_amount=>897500, :tax=>147500, :hotel_fees=>0, :base_fare=>750000, :currency=>"INR"}, 
    {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"} 
] 

p array.inject{|k,v| k.merge(v){|_,a,b| [a,b].all?{|e| e.is_a?(Fixnum)} ? (a+b)/2 : b}} 
# => {:amount=>952000, :gross_amount=>952000, :tax=>152000, :hotel_fees=>0, :base_fare=>800000, :currency=>"INR"} 

對於兩個或更多的哈希值在數組中,你可以嘗試使用:

main_array = [ 
    {:amount=>897500, :gross_amount=>897500, :tax=>147500, :hotel_fees=>0, :base_fare=>750000, :currency=>"INR"}, 
    {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"}, 
    {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"}, 
] 
array_result = main_array.flat_map(&:to_a).group_by(&:first).map do |key, array| 
    { 
    key => (
     result = array.inject(0) do |total, (_, value)| 
     value.is_a?(Fixnum) ? total + value : value 
     end 
     result.is_a?(Fixnum) ? result/main_array.size : result 
    ) 
    } 
end 
p array_result 
+0

'_,a,b |'中的'_'是什麼?你能解釋一下嗎? – Ravi

+0

@Ravi這是在我的答案中解釋,第一個屬性是關鍵,他稱之爲_第二個屬性是舊的值,或從第一個哈希值,第三個屬性是新值或第二個哈希值 –

+0

_這裏只是一個參數,他稱它爲一個隨機名稱,因爲他不會使用... –

3

厄貝沙坦

2.2.3 :011 > b = {test1: 30, test2: 40} 
=> {:test1=>30, :test2=>40} 
2.2.3 :012 > a = {test1: 20, test2: 60} 
=> {:test1=>20, :test2=>60} 
2.2.3 :013 > c = a.merge(b){|key, oldval, newval| (newval + oldval)/2} 
=> {:test1=>25, :test2=>50} 
+0

哦,我以爲這是別的東西。 – Ravi

2

由於merge僅適用於2和2,並且您在此處計算的平均值,因此接受的答案不適用於超過2個哈希值。

(((3 + 2)/2) + 2.5)/2 is different from (3 + 2 + 2.5)/3 

所以我寫了一段代碼,可以做你想做的無論什麼數組的大小,你有

def self.merge_all_and_average(array) 
    new_hash = {} 
    unless array.empty? 
     array[0].keys.each do |key| 
     if array[0][key].class == Fixnum 
      total = array.map { |i| i[key] }.inject(0) { |sum, x| sum + x } 
      new_hash = new_hash.merge(key => total/array.size) 
     else 
      new_hash = new_hash.merge(key => array[0][key]) 
     end 
     end 
    end 
    new_hash 
    end 
+0

我知道它不會工作超過兩個散列。我只想要一個關於如何處理它的想法。我在正確的道路上,但無法得到正確的答案。我的問題從來沒有完全不同,其他各種問題都涉及到。這只是我感到困惑的一部分。我用過的解決方案有點類似於你的解決方案。檢查我的編輯。 – Ravi

2

這應該與任何數量的散列的工作:

data = [ 
    { amount: 897_500, gross_amount: 897_500, tax: 147_500, hotel_fees: 0, base_fare: 750_000, currency: 'INR' }, 
    { amount: 1_006_500, gross_amount: 1_006_500, tax: 156_500, hotel_fees: 0, base_fare: 850_000, currency: 'INR' }, 
    { amount: 1_006_500, gross_amount: 1_006_500, tax: 156_500, hotel_fees: 0, base_fare: 850_000, currency: 'INR' } 
] 

transposed_hashes = data.each_with_object(Hash.new{|h, k| h[k] = []}) do |h, mem| 
    h.each do |k, v| 
    mem[k] << v 
    end 
end 
# {:amount=>[897500, 1006500, 1006500], :gross_amount=>[897500, 1006500, 1006500], :tax=>[147500, 156500, 156500], :hotel_fees=>[0, 0, 0], :base_fare=>[750000, 850000, 850000], :currency=>["INR", "INR", "INR"]} 

average_hash = transposed_hashes.map do |k, v| 
    new_value = if v[0].is_a? Integer 
       v.sum.to_f/v.size 
       else 
       v[0] 
       end 
    [k, new_value] 
end.to_h 

puts average_hash 
# {:amount=>970166.6666666666, :gross_amount=>970166.6666666666, :tax=>153500.0, :hotel_fees=>0.0, :base_fare=>816666.6666666666, :currency=>"INR"} 
+0

我也在做類似的工作,但這種方法增加了我的代碼複雜度。 – Ravi