The Array#any?, Array#all? RCR discussion reminded me of a snippet I had
tucked away for reducing an array (somewhat like folds in Haskell, and
‘reduce’ in several other languages). This can be used to check for #any?
and #all?, but certainly isn’t limited to it. I’ve added some unit tests–
because I should have created them in the first place (actually, I discovered
an error with flattening and Array#rreduce with them-- bonus!).
Usage is simple:
[1,2,3,4].reduce{ |a,b| a + b }
=> 10
%w|a lost puppy|.reduce{ |a,b| [a,b].join ’ ’ }
=> “a lost puppy”
[1,2,3,nil].reduce{ |a,b| a || b } # like Array#any?
=> 1
[1,2,3,nil].reduce{ |a,b| a && b } # like Array#all?
=> nil
Flattening and compacting can also be passed in as options:
[1,2,3,[nil,[1,2,nil]],4].reduce(:flatten, :compact){ |a,b| a + b }
=> 13
Just a fun little snippet someone may enjoy. Comments welcome, of course.
Regards,
// Bruce
–//snip//–
class Array
def reduce(*opts)
result = nil
if block_given?
items = dup
items.flatten! if opts.include? :flatten
items.compact! if opts.include? :compact
return if items.empty?
result = items.shift
items.each do |item|
result = yield result, item
end
end
result
end
def rreduce(*opts, &block)
if opts.include? :flatten
items = flatten.reverse
opts.delete :flatten
else
items = reverse
end
items.reduce(*opts, &block)
end
end
if FILE == $0
require ‘test/unit’
class ReduceTest < Test::Unit::TestCase
def testInt
assert_equal([1,2,3,4,5,6,7, 8].reduce{ |a,b| a + b }, 36)
end
def testStr
assert_equal([‘a’, ‘lazy’, ‘cat’].reduce{ |a,b| [a,b].join ’ ’ }, ‘a lazy
cat’)
assert_equal([‘a’, ‘lazy’, ‘cat’].reduce{ |a,b| [a,b.upcase].join ’ ’ }, ‘a
LAZY CAT’)
end
def testOptions
assert_equal([1,2,3,4,5,6,7,nil,nil,8].reduce(:compact){ |a,b| a + b }, 36)
assert_equal([1,2,[3,[4]],5,[6,7],8].reduce(:flatten){ |a,b| a + b }, 36)
assert_equal([1,2,[3,[4],nil],5,[6,7, nil],8].reduce(:flatten, :compact){
a,b| a + b }, 36)
end
def testNoBlock
assert_nil [1,2,3].reduce
end
def testEmpty
assert_nil [].reduce{ |a,b| a + b }
end
def testAll
all = proc{ |a,b| a && b }
assert_not_nil [1,2,3,4,5].reduce(&all)
assert_nil [1,2,3,4,nil,5].reduce(&all)
end
def testAny
any = proc{ |a,b| a || b }
assert_not_nil [1,2,3,4,5].reduce(&any)
assert_not_nil [1,2,3,4,nil,5].reduce(&any)
assert_nil [nil,nil,nil].reduce(&any)
end
end
class ReverseReduceTest < Test::Unit::TestCase
def testStr
assert_equal(['cat', 'lazy', 'a'].rreduce{ |a,b| [a,b.upcase].join ' ' },
‘a LAZY CAT’)
end
def testOptions
assert_equal([‘cat’, [‘lazy’, ‘a’, nil]].rreduce(:compact, :flatten){ |a,b|
[a,b.upcase].join ’ ’ }, ‘a LAZY CAT’)
end
end
end