My understanding was that Hash#select
and Hash#reject
each passes an array of key and its value [key, value]
as a single block argument for each iteration, and you can directly pick them separately within the block using implicit destructive assignment:
{a: 1, b: 2}.select{|k, v| k == :a} # => {:a => 1}
{a: 1, b: 2}.reject{|k, v| v == 1} # => {:b => 2}
or explicit destructive assignment:
{a: 1, b: 2}.select{|(k, v)| k == :a} # => {:a => 1}
I expected that, when I pass a unary block, the whole [key, value]
array would be passed, but in reality, it seems like the key is passed:
{a: 1}.select{|e| p e} # => Prints `:a` (I expected `[:a, 1]`)
Why does it work this way? For other Hash
instance methods like map
, the whole [key, value]
array is passed.
If it were especially designed to work differently for unary blocks as compared to binary blocks, then I can understand it is useful. But, then I would not understand why the case above with explicit destructive assignment works as is. And I also do not find any document mentioning such specification.
Edit I had a wrong result for {a: 1, b: 2}.reject{|(k, v)| v == 1}
. It is corrected here:
{a: 1, b: 2}.reject{|(k, v)| v == 1} # => {:a=>1, :b=>2} (not `{:b=>2}`)
Now, this also indicates that (k, v)
is the key
, not [key, value]
, so v
is always nil
. Cf. Darek Nędza's comment.