2013-09-25 4 views
4

У меня есть массив хэшей и хотел бы подвести выбранные значения. Я знаю, как их суммировать или один из них, но не как выбрать более одного ключа.Ruby: сумма выбранных значений хэша

т.е.

[{"a"=>5, "b"=>10, "active"=>"yes"}, {"a"=>5, "b"=>10, "active"=>"no"}, {"a"=>5, "b"=>10, "action"=>"yes"}] 

Суммируя все из них я с помощью:

t = h.inject{|memo, el| memo.merge(el){|k, old_v, new_v| old_v + new_v}} 
=> {"a"=>15, "b"=>30, "active"=>"yesnoyes"} # I do not want 'active' 

Подведем один ключ, я делаю:

h.map{|x| x['a']}.reduce(:+) 
=> 15 

Как я могу идти о подведении значения для ключей «a» и «b»?

+0

Почему бы просто не сделать 'h.map {| х | x ['a'] + x ['b']} .reduce (: +) '? –

+0

Спасибо @kardeiz за ваш комментарий. Но он возвращает 45. Я должен был сделать это яснее ... Я бы хотел: {'a' => 15, 'b' => 30} – Digger

ответ

6

Вы можете использовать values_at:

hs = [{:a => 1, :b => 2, :c => ""}, {:a => 2, :b => 4, :c => ""}] 
keys = [:a, :b] 
hs.map { |h| h.values_at(*keys) }.inject { |a, v| a.zip(v).map { |xy| xy.compact.sum }} 
# => [3, 6] 

Если все необходимые клавиши имеют значения, это будет короче:

hs.map { |h| h.values_at(*keys) }.inject { |a, v| a.zip(v).map(&:sum) } 
# => [3, 6] 

Если вы хотите Hash назад:

Hash[keys.zip(hs.map { |h| h.values_at(*keys) }.inject{ |a, v| a.zip(v).map(&:sum) })] 
# => {:a => 3, :b => 6} 
+0

'values_at' является идеальной отправной точкой для этого , +1 –

+1

Благодаря @VictorMoroz ваш пример Hash работал как шарм. Вы могли бы объяснить, что вы там делаете? Еще раз спасибо – Digger

2

Как это?

h = [{"a"=>5, "b"=>10, "active"=>"yes"}, {"a"=>5, "b"=>10, "active"=>"no"}, {"a"=>5, "b"=>10, "action"=>"yes"}] 
p h.map{|e| e.reject{|k,v| %w(active action).include? k } }.inject{|memo, el| memo.merge(el){|k, old_v, new_v| old_v + new_v}} 
# >> {"a"=>15, "b"=>30} 
3

Я хотел бы сделать что-то вроде этого:

a.map { |h| h.values_at("a", "b") }.transpose.map { |v| v.inject(:+) } 
#=> [15, 30] 

Шаг за шагом:

a.map { |h| h.values_at("a", "b") } #=> [[5, 10], [5, 10], [5, 10]] 
.transpose       #=> [[5, 5, 5], [10, 10, 10]] 
.map { |v| v.inject(:+) }   #=> [15, 30] 
+1

Спасибо @Stefan за ваш комментарий. Как добавить ключ к возвращенному массиву. Я ожидаю, что он вернется: {'a' => 15, 'b' => 30} – Digger

+0

'Hash [keys.zip (values)]', например. 'Hash [[" a "," b "]. Zip ([15, 30])]' – Stefan

Смежные вопросы