У меня есть массив целых чисел.
Например:
array = [123,321,12389]
Есть ли хороший способ получить их сумму?
Я знаю это
sum = 0
array.each { |a| sum+=a }
должно сработать.
У меня есть массив целых чисел.
Например:
array = [123,321,12389]
Есть ли хороший способ получить их сумму?
Я знаю это
sum = 0
array.each { |a| sum+=a }
должно сработать.
Ответы:
Попробуй это:
array.inject(0){|sum,x| sum + x }
Смотрите перечисляемую документацию Ruby
(примечание: 0
базовый случай необходим, чтобы 0
вместо пустого массива он возвращался nil
)
array.inject(:+)
более эффективен.
array.inject(:+)
кажется, вызывает проблемы в Ruby 1.8.6 Исключения «LocalJumpError: блок не указан» может появиться.
array.sum
может дать вам сумму значений массива.
reduce
псевдоним inject
(как в array.reduce( :+ )
).
inject
а не reduce
.
Или попробуйте Ruby 1.9:
array.inject(0, :+)
Примечание: 0
базовый регистр необходим, иначе nil
будет возвращен на пустых массивах:
> [].inject(:+)
nil
> [].inject(0, :+)
0
array.map(&:price).inject(0, :+)
немного безопаснее Это гарантирует, что если у вас есть пустой список, вы получите 0, а не ноль .
array.inject(0) { |sum, product| sum += product.price }
array.reduce(0, :+)
В то время как эквивалент array.inject(0, :+)
, термин сокращение входит в более общеупотребительный язык с ростом моделей программирования MapReduce .
Инъекция , уменьшение , свертывание , накопление и сжатие - это синонимы как класс функций свертывания . Я считаю согласованность всей вашей кодовой базы наиболее важной, но, поскольку различные сообщества предпочитают одно слово другому, тем не менее полезно знать альтернативы.
Чтобы подчеркнуть словосочетание «уменьшить карту», вот версия, которая немного более прощательна для того, что заканчивается в этом массиве.
array.map(&:to_i).reduce(0, :+)
Некоторые дополнительные соответствующие чтения:
reduce
говорит мне больше о том, что делает функция, но inject
звучит намного круче.
reduce
и map
в функции высшего порядка предшествует MapReduce. Вдохновение идет другим путем. И в смысле MapReduce, это несколько иная операция, чем простое функциональное сокращение, которое влияет на взаимодействие разных машин.
В качестве альтернативы (просто для сравнения), если у вас установлен Rails (фактически только ActiveSupport):
require 'activesupport'
array.sum
require 'active_support/core_ext/enumerable.rb'
или требовать все активной поддержки: require 'active_support/all'
. Подробнее об этом здесь: API Docs
activesupport
это массивное зависимость перетащить в проект , чтобы перейти от array.inject(:+)
к array.sum
.
require 'active_support/core_ext/enumerable'
без .rb
суффикса, поскольку он добавлен неявно.
Для Ruby> = 2.4.0 вы можете использовать sum
из Enumerables.
[1, 2, 3, 4].sum
Опасно для базовых классов mokeypatch. Если вам нравится опасность и вы используете более старую версию Ruby, вы можете добавить #sum
в Array
класс:
class Array
def sum
inject(0) { |sum, x| sum + x }
end
end
Вы можете использовать метко названный метод Enumerable#sum
. Он имеет много преимуществ по сравнению inject(:+)
с некоторыми важными примечаниями, которые нужно прочитать в конце.
(1..100).sum
#=> 5050
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
Этот метод не эквивалентен #inject(:+)
. Например
%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
Также,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)
Смотрите этот ответ для получения дополнительной информации о том, почему sum
это так.
Ruby 2.4+ / Rails - array.sum
т.е.[1, 2, 3].sum # => 6
Ruby pre 2.4 - array.inject(:+)
илиarray.reduce(:+)
* Примечание: этот #sum
метод является новым дополнением для 2.4, enumerable
так что теперь вы сможете использовать его array.sum
в чистом рубине, а не только в Rails.
Просто ради разнообразия вы можете сделать это, если ваш массив - это не массив чисел, а массив объектов, которые имеют свойства, которые являются числами (например, количество):
array.inject(0){|sum,x| sum + x.amount}
array.map(&:amount).inject(0, :+)
. Смотрите другие ответы.
map
затем inject
требует от вас циклически проходить по массиву дважды: один раз для создания нового массива, другой для суммирования членов. Этот метод немного более многословен, но и более эффективен.
Рубин 1.8.7 следующим образом:
array.inject(0, &:+)
Вы можете просто использовать:
example = [1,2,3]
example.inject(:+)
inject(:+)
а это нет inject :+
?
Достаточно
[1,2,3].inject('+')
Ruby 2.4.0 выпущен и имеет метод Enumerable # sum . Так что вы можете сделать
array.sum
Примеры из документов:
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
(1..10).sum #=> 55
(1..10).sum {|v| v * 2 } #=> 110
Также позволяет [1,2].sum{|x| x * 2 } == 6
:
# http://madeofcode.com/posts/74-ruby-core-extension-array-sum
class Array
def sum(method = nil, &block)
if block_given?
raise ArgumentError, "You cannot pass a block and a method!" if method
inject(0) { |sum, i| sum + yield(i) }
elsif method
inject(0) { |sum, i| sum + i.send(method) }
else
inject(0) { |sum, i| sum + i }
end
end
end
для массива с нулевыми значениями мы можем сделать компакт и затем ввести сумму
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)
Если вы чувствуете гольф, вы можете сделать
eval([123,321,12389]*?+)
Это создаст строку «123 + 321 + 12389», а затем с помощью функции eval сделает сумму. Это только для целей игры в гольф , вы не должны использовать его в надлежащем коде.
Способ 1:
[1] pry(main)> [1,2,3,4].sum
=> 10
[2] pry(main)> [].sum
=> 0
[3] pry(main)> [1,2,3,5,nil].sum
TypeError: nil can't be coerced into Integer
Способ 2:
[24] pry(main)> [].inject(:+)
=> nil
[25] pry(main)> [].inject(0, :+)
=> 0
[4] pry(main)> [1,2,3,4,5].inject(0, :+)
=> 15
[5] pry(main)> [1,2,3,4,nil].inject(0, :+)
TypeError: nil can't be coerced into Integer
from (pry):5:in `+'
Способ 3:
[6] pry(main)> [1,2,3].reduce(:+)
=> 6
[9] pry(main)> [].reduce(:+)
=> nil
[7] pry(main)> [1,2,nil].reduce(:+)
TypeError: nil can't be coerced into Integer
from (pry):7:in `+'
Способ 4: когда массив содержит нулевые и пустые значения, по умолчанию, если вы используете любые из вышеперечисленных функций, уменьшить, суммировать, внедрить все будет через
TypeError: nil не может быть приведен к Integer
Вы можете преодолеть это,
[16] pry(main)> sum = 0
=> 0
[17] pry(main)> [1,2,3,4,nil, ''].each{|a| sum+= a.to_i }
=> [1, 2, 3, 4, nil, ""]
[18] pry(main)> sum
=> 10
Метод 6: Eval
Оценивает выражения Ruby в строке.
[26] pry(main)> a = [1,3,4,5]
=> [1, 3, 4, 5]
[27] pry(main)> eval a.join '+'
=> 13
[30] pry(main)> a = [1,3,4,5, nil]
=> [1, 3, 4, 5, nil]
[31] pry(main)> eval a.join '+'
SyntaxError: (eval):1: syntax error, unexpected end-of-input
1+3+4+5+
Это самый короткий путь. Попробуй это.
array.inject :+
number = [1..100]
number. each do |n|
final_number = n.sum
puts "The sum is #{final_number}"
end
* Это хорошо работает для меня, как нового разработчика. Вы можете настроить диапазон номеров, изменив значения в пределах []
Вы также можете сделать это простым способом
def sum(numbers)
return 0 if numbers.length < 1
result = 0
numbers.each { |num| result += num }
result
end
Вы можете использовать .map и .sum как:
array.map { |e| e }.sum
array.sum
array.sum