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']
find
is implemented in terms ofeach
. Andeach
, when called on a Hash, returns key-value pairs in form of arrays with 2 elements each. That's whyfind
returns an array.The
Hash#detect
is inherited fromEnumerable#detect
method.Enumerable
module generates multiple methods(such assort
,min
,max
includingdetect
etc.) based on theeach
method of the class which includesEnumerable
.It doesn't care about how
each
is implemented as long as itSo for the
Hash#detect
method, it relies onHash#each
's behavior, which is:Because
Hash#each
yields the hash as two pair array, all methods inherited from theEnumerable
module works based on that.That's why
Hash#detect
produces a two elements array instead of the an hash object itself.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
output:
Two separate items, with the key as the first item and its corresponding value as the second item.
Output:
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”