module Enumerable
def reduce(empty_return=nil, &dyadic)
to_execute=lambda do |thus_far,every|
to_execute=dyadic
every
end
inject(empty_return) do |thus_far, every|
to_execute.call(thus_far,every)
end
end
end
require 'rubyunit'
class ReduceTest < Test::Unit::TestCase
def test_simple
result=[1,2,3,4,5].reduce {|thus_far,every| thus_far + every}
assert_equal(15, result)
end
def test_empty_nil
result=[].reduce {|result,every| thus_far + every}
assert_nil(result)
end
def test_empty_default
result=[].reduce(0) {|result,every| thus_far + every}
assert_equal(0, result)
end
end
It has a somewhat functional style in that instead of using a boolean to check for the first iteration, I just use a special lambda for the first pass and then it turns itself into the original one. There is some state (to_execute), but I'm still a functional newbie.
I do love inject, which has a lot of uses beyond aggregation, and this will reduce (no pun intended) code in some places where I use it.
Anyway, I couldn't stop myself. I thought wouldn't it be nice to just pass in a symbol instead of a block? I added the following method to Symbol and another test. Check it out:
class Symbol
def to_proc
lambda do |*arguments|
arguments.shift.send(self, *arguments)
end
end
end
class SymbolTest < Test::Unit::TestCase
def test_simple
result=[1,2,3,4,5].reduce &:+
assert_equal(15, result)
end
end
All I do is take a list of arguments. I make the first one the receiver and send the rest as it arguments. How cool is that? I get to cut down on the line noise. I still have to put up with &, but until they make blocks first class citizens...
What's the point of this post? Nothing. Just wanted to do a fun little exercise. I thought others might find the implementation fun as well. Now, about that name 'reduce'...I think maybe aggregate would be better? But, that doesn't express for all cases either. Hmmm...
1 comment:
Um...
[1,2,3,4].inject() {|a,b| a + b} # 10
Post a Comment