Ruby 散列中特定值的总和
Sum of particular values in a Ruby hash
我有两个哈希:
first = { 1 => [15, 15, 15, 8], 4 => [11, 12, 7, 7], 5 => [14, 17, 13, 13],
6 => [19, 19, 15, 15], 7 => [5, 12, 12, 12], 8 => [10, 14, 14, 14],
9 => [8, 7, 8, 8] }
second = { 1 => [0, 1, 2], 4 => [2, 3], 5 => [2, 3], 6 => [0, 1, 2, 3],
7 => [1, 2, 3], 8 => [1, 2, 3], 9 => [2, 3] }
如您所见,它们都使用相同的键,但值不同。 second
的值包含 first
的值的索引范围,我只需要对那些在这些范围内的 first
的值求和。
预期输出:
result = { 1 => [45], 4 => [14], 5 => [26], etc }
一个直接的方法就是准确地说出你的意思:
first.map { |k, v| [ k, [ v.values_at(*second[k]).sum ] ] }.to_h
如果您的 Ruby 版本没有 Array#sum
则使用 inject(:+)
:
first.map { |k, v| [ k, [ v.values_at(*second[k]).inject(:+) ] ] }.to_h
您也可以使用 each_with_object
来跳过 map
/to_h
业务:
first.each_with_object({}) { |(k, v), h| h[k] = [ v.values_at(*second[k]).inject(:+) ] }
Array#values_at
documentation might be fruitful as would the Enumerable
documentation.
的一点时间
试试这个:
def sum(list, indices)
sum = 0
indices.each do |index|
sum += list[index]
end
return sum
end
然后
second.map { |k, v| [k, sum(first[k], v)] }.to_h
更自然的方式是使用Hash#merge
,我认为:
first.merge(second) { |_, f, s| [f.values_at(*s).sum] }
#=> {1=>[45], 4=>[14], 5=>[26], 6=>[68], 7=>[36], 8=>[42], 9=>[16]}
当然,如果您的 Ruby 版本 < 2.4
,您可以使用 inject(:+)
而不是 sum
既然你说 second
的元素是范围,你可以这样写:
second = { 1=>0..2, 4=>2..3, 5=>2..3, 6=>0..3, 7=>1..3, 8=>1..3, 9=>2..3 }
然后
second.merge(second) { |k,o,_| first[k].values_at(*o).sum }
#=> {1=>45, 4=>14, 5=>26, 6=>68, 7=>36, 8=>42, 9=>16}
这使用 Hash#merge 的形式,它使用一个块来确定要合并的两个哈希中存在的键的值,这里是所有键。有关详细信息,请参阅文档,特别是三个块变量 k
、o
和 n
的值。 (这里我用 _
替换了 n
以表示它不用于块计算。)
我有两个哈希:
first = { 1 => [15, 15, 15, 8], 4 => [11, 12, 7, 7], 5 => [14, 17, 13, 13],
6 => [19, 19, 15, 15], 7 => [5, 12, 12, 12], 8 => [10, 14, 14, 14],
9 => [8, 7, 8, 8] }
second = { 1 => [0, 1, 2], 4 => [2, 3], 5 => [2, 3], 6 => [0, 1, 2, 3],
7 => [1, 2, 3], 8 => [1, 2, 3], 9 => [2, 3] }
如您所见,它们都使用相同的键,但值不同。 second
的值包含 first
的值的索引范围,我只需要对那些在这些范围内的 first
的值求和。
预期输出:
result = { 1 => [45], 4 => [14], 5 => [26], etc }
一个直接的方法就是准确地说出你的意思:
first.map { |k, v| [ k, [ v.values_at(*second[k]).sum ] ] }.to_h
如果您的 Ruby 版本没有 Array#sum
则使用 inject(:+)
:
first.map { |k, v| [ k, [ v.values_at(*second[k]).inject(:+) ] ] }.to_h
您也可以使用 each_with_object
来跳过 map
/to_h
业务:
first.each_with_object({}) { |(k, v), h| h[k] = [ v.values_at(*second[k]).inject(:+) ] }
Array#values_at
documentation might be fruitful as would the Enumerable
documentation.
试试这个:
def sum(list, indices)
sum = 0
indices.each do |index|
sum += list[index]
end
return sum
end
然后
second.map { |k, v| [k, sum(first[k], v)] }.to_h
更自然的方式是使用Hash#merge
,我认为:
first.merge(second) { |_, f, s| [f.values_at(*s).sum] }
#=> {1=>[45], 4=>[14], 5=>[26], 6=>[68], 7=>[36], 8=>[42], 9=>[16]}
当然,如果您的 Ruby 版本 < 2.4
,您可以使用inject(:+)
而不是 sum
既然你说 second
的元素是范围,你可以这样写:
second = { 1=>0..2, 4=>2..3, 5=>2..3, 6=>0..3, 7=>1..3, 8=>1..3, 9=>2..3 }
然后
second.merge(second) { |k,o,_| first[k].values_at(*o).sum }
#=> {1=>45, 4=>14, 5=>26, 6=>68, 7=>36, 8=>42, 9=>16}
这使用 Hash#merge 的形式,它使用一个块来确定要合并的两个哈希中存在的键的值,这里是所有键。有关详细信息,请参阅文档,特别是三个块变量 k
、o
和 n
的值。 (这里我用 _
替换了 n
以表示它不用于块计算。)