问题
#each_with_object and #inject can both be used to build a hash.
For example:
matrix = [['foo', 'bar'], ['cat', 'dog']]
some_hash = matrix.inject({}) do |memo, arr|
memo[arr[0]] = arr
memo # no implicit conversion of String into Integer (TypeError) if commented out
end
p some_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]}
another_hash = matrix.each_with_object({}) do |arr, memo|
memo[arr[0]] = arr
end
p another_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]}
One of the key differences between the two is #each_with_object
keeps track of memo
through the entire iteration while #inject
sets memo
equal to the value returned by the block on each iteration.
Another difference is the order or the block parameters.
Is there some intention being communicated here? It doesn't make sense to reverse the block parameters of two similar methods.
回答1:
They have a different ancestry.
each_with_object
has been added to Ruby 1.9 in 2007inject
goes back to Smalltalk in 1980
I guess if the language were designed with both methods from the begin they would likely expect arguments in the same order. But this is not how it happened. inject
has been around since the begin of Ruby whereas each_with_object
has been added 10 years later only.
inject
expects arguments in the same order as Smalltalk's inject:into:
collection inject: 0 into: [ :memo :each | memo + each ]
which does a left fold. You can think of the collection as a long strip of paper that is folded up from the left and the sliding window of the fold function is always the part that has already been folded plus the next element of the remaining paper strip
# (memo = 0 and 1), 2, 3, 4
# (memo = 1 and 2), 3, 4
# (memo = 3 and 3), 4
# (memo = 6 and 4)
Following the Smalltalk convention made sense back then since all the initial methods in Enumerable
are taken from Smalltalk and Matz did not want to confuse people who are familiar with Smalltalk.
Nor could anyone have the foresight to know that would happen in 2007 when each_with_object
was introduced to Ruby 1.9 and the order of argument reflects the lexical order of the method name, which is each ... object
.
And hence these two methods expect arguments in different orders for historical reasons.
来源:https://stackoverflow.com/questions/41783001/why-would-each-with-object-and-inject-switch-the-order-of-block-parameters