Вы можете сделать это в несколько этапов:
>> a = [[1, 2], [2, 3], [3, 8], [4, 2]]
>> a.select { |e| e.first <= 1 }.inject(0) { |s, e| s += e.last }
=> 2
>> a.select { |e| e.first <= 1 }.map(&:last).inject(0, :+)
=> 2
Выполнение всего с одним inject
должно быть более эффективным, но разбить его на куски может быть чище, и разница в скорости не будет заметнаесли у вас нет действительно больших массивов.
Если вы не возражаете против эмуляции указателя с помощью хэша или массива, вы можете сделать это с помощью each_with_object
:
>> a.each_with_object({ :sum => 0 }) { |(k,v), m| m[:sum] += v if k <= 1 }[:sum]
=> 2
>> a.each_with_object([0]) { |(k,v), m| m[0] += v if k <= 1 }.first
=> 2
Результат вашегоБлок inject
используется как значение s
при следующем вызове вашего блока.На втором итераторе это:
s + e[1] if e[0] <= 1
будет иметь значение nil
, потому что e[0]
будет 2. Последующие итерации также возвращают nil
из вашего блока, потому что каждый e[0]
больше, чем1 кроме первого.Вот почему вам нужно вернуть s
из вашего блока.Если бы у вас был такой массив:
[[1, 2], [2, 3], [3, 8], [4, 2], [1, 11]]
, вы бы даже не получили nil
из вашего inject
, вы просто могли бы сделать исключение:
NoMethodError: undefined method `+' for nil:NilClass
когда ваш блок попытался добавить 11 к nil
.