что мне не нравится в принятом решении
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
заключается в том, что он не работает чисто функционально.
нам нужна переменная arr для вычисления arr.size в конце.
, чтобы решить это чисто функционально, нам нужно отслеживать два
значения: сумма всех элементов и количество элементов.
[5, 6, 7, 8].inject([0.0,0]) do |r,ele|
[ r[0]+ele, r[1]+1 ]
end.inject(:/)
=> 6.5
Santhosh улучшил это решение: вместо аргумента r, являющегося массивом, мы могли бы использовать деструктуризацию, чтобы сразу выделить его на две переменные
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
[ sum + ele, size + 1 ]
end.inject(:/)
если вы хотите увидеть, как это работает, добавьте несколько пут:
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
r2 = [ sum + ele, size + 1 ]
puts "adding #{ele} gives #{r2}"
r2
end.inject(:/)
adding 5 gives [5.0, 1]
adding 6 gives [11.0, 2]
adding 7 gives [18.0, 3]
adding 8 gives [26.0, 4]
=> 6.5
Мы могли бы также использовать структуру вместо массива, чтобы содержать сумму и количество, но затем мы должны сначала объявить структуру:
R=Struct.new(:sum, :count)
[5, 6, 7, 8].inject( R.new(0.0, 0) ) do |r,ele|
r.sum += ele
r.count += 1
r
end.inject(:/)