Моим самым первым инстинктом было: «Это, очевидно, сканирование (он же префикс-сумма), так что это должно быть легко»:
[1, 5, 8, 11, -6].scan(:+)
Очевидно, что в последнее время я слишком много читаю на Haskell и Scala, потому что в Ruby & hellip нет Enumerable#scan
; еще:
module Enumerable
def scan(initial=first, &block)
[initial].tap {|res|
reduce {|acc, el|
block.(acc, el).tap {|el|
res << el
}
}
}
end
end
Если вы хотите, чтобы Enumerable#scan
вел себя как Enumerable#reduce
, т.е. принимал необязательный начальный аргумент и необязательный символ, нам нужно немного улучшить нашу версию с помощью некоторого аргумента, массирующего код, украденный из Enumerable#reduce
Рубиниуса:
module Enumerable
def scan(initial=nil, sym=nil, &block)
args = if initial then [initial] else [] end
unless block_given?
args, sym, initial = [], initial, first unless sym
block = ->(acc, el) { acc.send(sym, el) }
end
[initial || first].tap {|res|
reduce(*args) {|acc, el|
block.(acc, el).tap {|e|
res << e
}
}
}
end
end
В этой расширенной версии теперь работает приведенный выше пример:
p [1, 5, 8, 11, -6].scan(:+)
# => [1, 6, 14, 25, 19]
Если у вас снова возникла такая проблема, на другом языке запомните термины scan и prefix-sum , такие функции обычно довольно распространены. Я не совсем понимаю, почему у Руби их уже нет.