簡體   English   中英

Sum ruby​​哈希值

[英]Sum ruby hash values

我試圖從ruby散列中求和值,但使用inject或reduce不會返回正確的答案。 看起來這些方法似乎覆蓋了存儲的當前值而不是對它們求和。

我的哈希看起來像這樣:

@test = [
  {"total"=>18, "type"=>"buy", "date"=>Thu, 21 Nov 2013, "instrument_code"=>"food"},
  {"total"=>92, "type"=>"buy", "date"=>Thu, 14 Nov 2013, "instrument_code"=>"food"},
  {"total"=>12, "type"=>"buy", "date"=>Wed, 20 Nov 2013, "instrument_code"=>"drink"},
  {"total"=>1, "type"=>"buy", "date"=>Mon, 11 Nov 2013, "instrument_code"=>"food"}
]

這是我的注入代碼失敗:

def additions_per_security
  @test.group_by { |i| i.type }.each do |key, value|
    if key == "buy"
      value.group_by{ |i| i.date }.each do |key, value|
        @sortable_additions[key] = value
      end
      @sorted_additions = @sortable_additions.sort_by { |key,value| key }
      @sorted_additions.shift
      @additions_per_security = Hash[@sorted_additions.map { |key, value| 
       [key, value]
      }]
      @additions_per_security.each do |key, value|
        value.group_by { |i| i.instrument_code }.each do |key, value|
          @additions_security[key] = value.inject(0){ |result, transaction| 
            (result += transaction.total)
          }
        end
      end
    end
  end
  return @additions_security
end

這是我的reduce代碼失敗:

def additions_per_security
  @@test.group_by { |i| i.type }.each do |key, value|
    if key == "buy"
      value.group_by { |i| i.date }.each do |key, value|
        @sortable_additions[key] = value
      end
      @sorted_additions = @sortable_additions.sort_by { |key,value| key }
      @sorted_additions.shift
      @additions_per_security = Hash[@sorted_additions.map { |key, value| 
        [key, value]
      }]
      @additions_per_security.each do |key, value|
        value.group_by { |i| i.instrument_code }.each do |key, value|
          @additions_security[key] = value.map { |p| p.total }.reduce(0,:+)
        end
      end
    end
  end
  return @additions_security
end

我有一個哈希,我想要除了第一個日期之外的所有鍵的總和。

我目前正在收到以下信息:

{"drink"=>12.0, "food"=>92}

我的預期結果將如下所示:

{"drink"=>12.0, "food"=>110}

提前感謝任何建議。

如果你有簡單的鍵/值哈希

{1 => 42, 2 => 42}.values.sum
 => 84 

我對您的inject代碼提供以下觀察:

  • 沒有變量需要是實例變量; 局部變量(沒有@ )就足夠了;
  • test.group_by {|i| i.type}... test.group_by {|i| i.type}...應該是test.group_by {|i| i["type"]}... test.group_by {|i| i["type"]}...
  • @sortable_additions[key]=value應引發異常,因為尚未創建哈希;
  • @sorted_additions.shift刪除哈希的第一個元素並返回該元素,但是沒有變量可以接收它(例如, h = @sorted_additions.shift );
  • @additions_per_security = Hash[@sorted_additions.map { |key, value|[key, value]}]似乎將@sorted_additions轉換為數組,然后返回相同的哈希值。

以下是一種做你想做的事情的方法。

首先,您將傳遞日期對象。 為了解決這個問題,我們首先為您示例中的日期創建日期對象:

require 'date'
date1 = Date.parse("Thu, 21 Nov 2013") # => #<Date: 2013-11-21 ((2456618j,0s,0n),+0s,2299161j)>
date2 = Date.parse("Thu, 14 Nov 2013") # => #<Date: 2013-11-14 ((2456611j,0s,0n),+0s,2299161j)>
date3 = Date.parse("Thu, 20 Nov 2013") # => #<Date: 2013-11-20 ((2456617j,0s,0n),+0s,2299161j)>
date4 = Date.parse("Thu, 11 Nov 2013") # => #<Date: 2013-11-11 ((2456608j,0s,0n),+0s,2299161j)>

用於檢測:

test = [{"total"=>18, "type"=>"buy", "date"=>date1, "instrument_code"=>"food"},
        {"total"=>92, "type"=>"buy", "date"=>date2, "instrument_code"=>"food"},
        {"total"=>12, "type"=>"buy", "date"=>date3, "instrument_code"=>"drink"},
        {"total"=> 1, "type"=>"buy", "date"=>date4, "instrument_code"=>"food"}]

現在我們計算我們需要的東西。

test_buy = test.select {|h| h["type"] == "buy"}

earliest = test_buy.min_by {|h| h["date"]}["date"]
  # => #<Date: 2013-11-11 ((2456608j,0s,0n),+0s,2299161j)>

all_but_last = test.reject {|h| h["date"] == earliest}
 # =>  [{"total"=>18, "type"=>"buy", "date"=>date1, "instrument_code"=>"food"},
        {"total"=>92, "type"=>"buy", "date"=>date2, "instrument_code"=>"food"},
        {"total"=>12, "type"=>"buy", "date"=>date3, "instrument_code"=>"drink"}] 

或者我們可以使用Enumerable#select

all_but_last = test.select {|h| h["date"] != earliest}

請注意,此處和下方將顯示date1date2date3的值(例如, #<Date: 2013-11-21 ((2456618j,0s,0n),+0s,2299161j)>將顯示date1 ) ; 我在這里使用變量名作為占位符,以使其更具可讀性。 此外,所有哈希hh["date"] = earliest將被拒絕(如果有多個)。

grouped = all_but_last.group_by {|h| h["instrument_code"]}
 # => {"food" =>[{"total"=>18, "type"=>"buy", "date"=>date1, "instrument_code"=>"food"},
                  {"total"=>92, "type"=>"buy", "date"=>date2, "instrument_code"=>"food"}],
       "drink"=>[{"total"=>12, "type"=>"buy", "date"=>date3, "instrument_code"=>"drink"}]}

keys = grouped.keys # => ["food", "drink"]

arr = keys.map {|k| [k, grouped[k].reduce(0) {|t,h| t + h["total"]}]}
  # => [["food", 110], ["drink", 12]]

Hash[arr] # => {"food"=>110, "drink"=>12} 

我使用了一些臨時變量,包括test_buyearliestall_but_lastgroupedkeysarr 您可以通過“鏈接”來消除其中的一些。 在這里,我將向您展示如何擺脫其中一些:

test_buy = test.select {|h| h["type"] == "buy"}
earliest = test_buy.min_by {|h| h["date"]}["date"]
grouped = test_buy.reject {|h| h["date"] == earliest}.group_by \
  {|h| h["instrument_code"]}
Hash[grouped.keys.map {|k| [k, grouped[k].reduce(0) \
  {|t,h| t + h["total"]}]}] # => {"food"=>110, "drink"=>12}

您可能認為這看起來很復雜,但在您獲得Ruby經驗后,它看起來非常自然且易於閱讀。 但是,使用鏈接的程度是樣式首選項。

嘗試:

test = [
    {"total"=>18, "type"=>"buy", "date"=>Thu, 21 Nov 2013, "instrument_code"=>"food"},
    {"total"=>92, "type"=>"buy", "date"=>Thu, 14 Nov 2013, "instrument_code"=>"food"},
    {"total"=>12, "type"=>"buy", "date"=>Wed, 20 Nov 2013, "instrument_code"=>"drink"},
    {"total"=>1, "type"=>"buy", "date"=>Mon, 11 Nov 2013, "instrument_code"=>"food"}
]

except_first_date = test.sort_by {|i| i['date'] }
except_first_date.shift

result = except_first_date.inject({}) {|m,i| m[i["instrument_code"]] = m[i["instrument_code"]].to_f + i['total'] ; m }
# => {"food"=>110.0, "drink"=>12.0}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM