All variable names have been changed to protect the innocent. Likeness to any variables presently in or out of scope is purely coincidental.
Got caught by the following snippet this morning:
# given a heterogeneous array,
# I'm only interested in positive integers
# and I really only need one
first_positive_integer = array.reduce([]) do |memo, obj|
memo << obj.to_i if obj.to_i > 0
end.first
Note: to_i
returns 0
if it can't parse an integer from the start of whatever it's called on.
Upon testing I was suprised to find that Ruby slapped me with
NoMethodError: undefined method 'first' for nil:NilClass
depending on the non-numerical contents of array
.
A quick jump across to Dash helped me realise that I had forgotten how reduce
/inject
actually replaces memo
with the result of the block - the block yields nil
if the conditional fails.
After a swift facepalm I looked at possible fixes:
# actually push the nil and then filter
first_positive_integer = array.reduce([]) do |memo, obj|
memo << (obj.to_i if obj.to_i > 0)
end.reject(&:nil?).first
# extract the accumulator
memo = []
array.map do |obj|
memo.push(obj.to_i) if obj.to_i > 0
end
first_positive_integer = memo.first
I chose the latter for readability.