#!/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