0

我有两个哈希:

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 }
4

4 回答 4

8

一个直接的方法是准确地说出你的意思:

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

您也可以通过使用来跳过map/to_h业务each_with_object

first.each_with_object({}) { |(k, v), h| h[k] = [ v.values_at(*second[k]).inject(:+) ] }

Array#values_at与文档花一点时间可能会很有成效,Enumerable文档也会如此。

于 2017-04-04T16:48:16.707 回答
3

更自然的方式是使用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

于 2017-04-04T17:15:23.560 回答
2

既然你说的元素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_表示它不用于块计算。)

于 2017-04-04T17:59:26.197 回答
1

试试这个:

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

于 2017-04-04T16:54:04.417 回答