#!/usr/bin/ruby -w
# A reduce function (generalised inject) [ruby-talk:03178]
#
# Scheme's reduce:
# (reduce + 0 '(1 2 3 4)) => 10
# (reduce * 0 '(1 2 3 4)) => 24
#
# APL's /:
# +/1 2 3 4 => 10
# +/2 2 rho 2 3 5 7 => 5 12
# an interesting property of the APL one is that it applies right to left so
# that -/ has a different meaning than -+/, that is, instead of returning the
# negation of a summation, it returns an alternated sum. you get (-1)^n for
# free. similarly, you can do power towers with */ (where * is the power
# operator)
def reduce(fn, res, *vals)
vals.each { |v|
res = res.send(fn, v)
}
res
end
p reduce(:*, 1, 2, 3, 4, 5) # -> 120
p reduce(:+, 'cat', 'dog', 'horse') # -> catdoghorse
p reduce(:|, 1, 16, 64) # -> 81
# Place the methods in the module Enumerable, and they automatically
# work with all collections:
module Enumerable
def reduce(fn, res)
each { |n| res = res.send(fn, n) }
res
end
def reduceBlock(res)
each { |n| res = yield(res, n) }
res
end
end
p [1,2,3,4,5,6].reduce(:*, 1) # => 720
p %w(cat dog horse).reduce(:+, '') # => catdoghorse
puts((1..5).reduceBlock(0) { |res, n| res + n }) # => 15
p %w(cat dog horse).reduceBlock('Animals: ') { |res, n| res + n }
# => Animals: catdoghorse