Created
August 16, 2012 15:23
-
-
Save cupakromer/3371003 to your computer and use it in GitHub Desktop.
each_with_object vs inject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
my_array = %w[test one two three] | |
# Inject takes the value of the block and passes it along | |
# This often causes un-intended errors | |
my_array.inject({}) do |transformed, word| | |
puts transformed | |
transformed[word] = word.capitalize | |
end | |
# Output: | |
# {} | |
# Test | |
# IndexError: string not matched | |
# from (pry):6:in `[]=' | |
# What was really wanted was: | |
my_array.inject({}) do |transformed, word| | |
puts transformed | |
transformed[word] = word.capitalize | |
transformed | |
end | |
# Output: | |
# {} | |
# {"test"=>"Test"} | |
# {"test"=>"Test", "one"=>"One"} | |
# {"test"=>"Test", "one"=>"One", "two"=>"Two"} | |
=> {"test"=>"Test", "one"=>"One", "two"=>"Two", "three"=>"Three"} | |
# On the other hand, each_with_object does exactly as you expect | |
# It ignores the return value of the block and only passes the | |
# initial object along | |
my_array.each_with_object({}) do |word, transformed| | |
puts transformed | |
transformed[word] = word.capitalize | |
"this is ignored" | |
end | |
# Output: | |
# {} | |
# {"test"=>"Test"} | |
# {"test"=>"Test", "one"=>"One"} | |
# {"test"=>"Test", "one"=>"One", "two"=>"Two"} | |
=> {"test"=>"Test", "one"=>"One", "two"=>"Two", "three"=>"Three"} |
Annoying that the order of the parameters is different - I understand 'inject' is historical and 'with_object' is just doing what 'with_index' does - but it's annoying nonetheless.
@liznet If you're talking about #inject
, it's useful for a lot of things. If you're talking about #each_with_object
it's only good for objects with mutable state (which is the thing I was think about when I ran across this thread).
['t', 'l', 'k'].each_with_object('sass'){ |letter, word| word.sub! 's', letter }
# => "talk"
Or an ever so slightly less contrived example
# yes, i realize it's permutations not combinations
class Lock
def initialize(*combo)
@combo = combo
@attempt_values = []
@locked = true
end
def turn_to(value)
@attempt_values << value
end
def locked?
@combo != @attempt_values
end
end
combo = [1, 2, 3]
combo.each_with_object(Lock.new(3, 2, 1)){ |value, lock| lock.turn_to value }.locked?
# => true
combo.each_with_object(Lock.new(1, 2, 3)){ |value, lock| lock.turn_to value }.locked?
# => false
My realization was that if I wanted a pure function approach, it's only feasible to use #inject
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It works only for creating hash. right?