我有一個哈希
{:a => 2, :b => 8, :c => 10, :d => 40 }
我想修改哈希值,以便這些值代表一個運行總數。
{:a => 2, :b => 10, :c => 20, :d => 60 }
我走了幾條路,但沒有找到正確的答案。我嘗試過的一些事情。
data.inject({}) { |result, (k,v)| result[k] = v result.values.compact.sum; result }
=> {:a=>2, :b=>10, :c=>22, :d=>74}
我顯然不太明白結果是如何在注入中累積的。由于 k 的第一次迭代為零,我正在使用緊湊型。
我可以像這樣將值作為陣列獲取
data.inject([]) { |result, element| result << result.last.to_i element.last }
=> [2, 10, 20, 60]
我不知道如何修改它以與哈希類似地作業。
我可以這樣做,但這似乎不是正確/最有效的方法。
totals = data.inject([]) { |result, element| result << result.last.to_i element.last }
=> [2, 10, 20, 60]
data.map.with_index { |(k,v),i| [k,totals[i]] }.to_h
=> {:a=>2, :b=>10, :c=>20, :d=>60}
感謝我能在這里得到的任何幫助。
uj5u.com熱心網友回復:
鑒于您知道鍵的順序,您可以簡單地撰寫
h= { :a => 2, :b => 8, :c => 10, :d => 40 }
cumulative = 0
h.transform_values { |v| cumulative = v }
#=> {:a=>2, :b=>10, :c=>20, :d=>60}
請參閱Hash#transform_values。
uj5u.com熱心網友回復:
您的“inject和map.with_index”很接近,但您可以將它們組合起來:
data.inject({}) { |h, (k, v)| h.merge(k => v h.values.last.to_i) }
或減少復制:
data.inject({}) { |h, (k, v)| h.merge!(k => v h.values.last.to_i) }
也許:
data.each_with_object({}) { |(k, v), h| h[k] = v h.values.last.to_i }
h開始是空的,所以h.values可以是空的,所以h.values.last.nil?會發生,因此#to_i呼叫“隱藏”nil測驗并簡化塊。
uj5u.com熱心網友回復:
哈希和排序
哈希不能保證按排序順序排列,因此您可以保持運行總計的前提(原則上)是無效的,除非您在將值傳遞給 #inject 或 #reduce 之前對鍵進行排序。但是,MRI Ruby 通常會按插入順序保留哈希,但請自行承擔風險。
解決方案
拋開你的哈希的排序順序,你可以用 #sort 或 #sort_by 來解決,如果你愿意,可以進行一些重構,我會在 Ruby 3.0.2 中像這樣修改原始哈希:
hash = {:a => 2, :b => 8, :c => 10, :d => 40 }
# Note that positional argument `_1` is the
# accumulator, and `_2` is the value.
hash = hash.keys.zip(
hash.values.inject([]) { _1 << _2 _1&.last.to_i }
).to_h;
hash
#=> {:a=>2, :b=>10, :c=>20, :d=>60}
如果您不想分配回相同的 Hash,或者想將結果分配到其他地方,您也可以這樣做。但是,正如我所理解的問題是關于就地修改散列,將運算式的結果分配回散列似乎是最簡單的事情。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/334372.html
