Why does Enumerable#find/#detect return an Array even when called on an Hash?

你说的曾经没有我的故事 提交于 2019-12-22 04:01:19

问题


The documentation for Enumerable#find/#detect says:

find(ifnone = nil) { |obj| block } → obj or nil
find(ifnone = nil) → an_enumerator

Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns nil otherwise.

However, when it is called on the Hash, the result has changed the type to Array instead of the original Hash.

Is it some implementation fault or some historical conventions regarding this datatype?

{a: 'a', b:'b'}.find {|k, v| v == 'b'}
# => [:b, 'b']

回答1:


The Hash#detect is inherited from Enumerable#detect method.

Enumerable module generates multiple methods(such as sort, min, max including detect etc.) based on the each method of the class which includes Enumerable.

It doesn't care about how each is implemented as long as it

"...yields successive members of the collection. " from ruby-doc

So for the Hash#detect method, it relies on Hash#each's behavior, which is:

Calls block once for each key in hsh, passing the key-value pair as parameters. If no block is given, an enumerator is returned instead.

h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }

Because Hash#each yields the hash as two pair array, all methods inherited from the Enumerable module works based on that.

That's why Hash#detect produces a two elements array instead of the an hash object itself.




回答2:


find is implemented in terms of each. And each, when called on a Hash, returns key-value pairs in form of arrays with 2 elements each. That's why find returns an array.




回答3:


Using detect/find with Hashes

With hashes, detect/find passes each key/value pair in the hash to the block, which you can “catch” as either:

A two-element array, with the key as element 0 and its corresponding value as element 1, or

h = {:a => 'a', :b => 'b'}
p h.find {|k| p k ; k[1] == 'b'}

output:

[:a, "a"]
[:b, "b"]
[:b, "b"]

Two separate items, with the key as the first item and its corresponding value as the second item.

h = {:a => 'a', :b => 'b'}
p h.find {|k, v| puts k,v ; v == 'b'}

Output:

a
a
b
b
[:b, "b"]

To get more on this topic look here Enumerating Ruby’s “Enumerable” Module, Part 3: “detect”, a.k.a. “find”Enumerating Ruby’s “Enumerable” Module, Part 3: “detect”, a.k.a. “find”



来源:https://stackoverflow.com/questions/16250746/why-does-enumerablefind-detect-return-an-array-even-when-called-on-an-hash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!