Feature #14788
open`Hash#keys` Could Accept a Block
Description
Sometimes I only need to fetch some of the keys from a Hash. With the current Hash#keys
implementation, this requires fetching all the keys and then selecting the ones I'm interested in. It would be nice if Has#keys
accepted a block, and only returned the keys for which the block evaluated to true.
Currently:
{ 1 => '1', 2 => '2', 3 => '3', 4 => '4' }.keys.select { |key| key.odd? } # => [1, 3]
Proposed:
{ 1 => '1', 2 => '2', 3 => '3', 4 => '4' }.keys { |key| key.odd? } # => [1, 3]
The attached patch shows how rb_hash_keys
might be modified to check for a passed block.
Files
Updated by rringler (Ryan Ringler) over 6 years ago
- Tracker changed from Bug to Feature
- Backport deleted (
2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN)
Updated by rringler (Ryan Ringler) over 6 years ago
- File hash_keys_block.patch hash_keys_block.patch added
- File deleted (
hash_keys_block.patch)
Updated by Hanmac (Hans Mackowiak) over 6 years ago
I don't like it.
From keys {|k| k.something }
I wouldn't know what it does with the keys, if they would select or map the keys or both.
Is probably against that "least surprise" thing
Updated by sawa (Tsuyoshi Sawada) over 6 years ago
If I were you, I would rather request a new method named Hash#select_keys
for that purpose.
Updated by shevegen (Robert A. Heiler) over 6 years ago
I personally understand what Ryan suggested and meant; the example shows that he
can integrate the ".select" step .keys, through the use of block.
To me the example is also readable and the intent is clear, so in that particular
case, "object.odd?" queries whether the object in question, aka our key, is odd
or is not. Although one limitation obviously is that the object must respond to
.odd? or we'd otherwise safeguard calling on it (and return false in this case,
I guess?).
I think that the .select option is still clearer though, although more verbose.
In ruby I think it is really "rubyish" to use .select .reject, or the new alias
.filter. It's very clear and very simple IMO.
If the primary concern of the issue is about speed and efficiency, then I think
what Tsuyoshi Sawada makes sense, and a new method should be added (and you may
have to convince matz; I think Tsuyoshi suggested lots of features, some of
which were accepted).
If the primary aim is to omit .select, though, then I am not sure if the use
case described is ideal since it referred to speed/efficiency mostly (in other
words, to not get a full array result when we use .keys there).
Hanmac wrote:
Is probably against that "least surprise" thing
Well, there is not really "one universal least surprise". Matz said
that once, when people are different, have different expectations etc..
What to expect of C++ too. :-)
In this case, I somewhat agree with your point, although I am actually
neutral since I don't mind either way.
Anyway, I guess it is up to Ryan whether he wants to modify the suggestion
or not; it's his suggestion after all. I would recommend to also consider
Tsuyoshi's suggestion though, even though it is different (e. g. a new
method, versus modify an existing method). I guess ultimately it comes
down as to what any ruby hacker would naively assume .keys on class
Hash to do when a block is issued to it. I myself would not know, but
as said, I am mostly really neutral here, just adding some thoughts.
Updated by znz (Kazuhiro NISHIYAMA) over 6 years ago
How about each_key
?
{ 1 => '1', 2 => '2', 3 => '3', 4 => '4' }.each_key.select(&:odd?) # => [1, 3]
Updated by jacobevelyn (Jacob Evelyn) over 4 years ago
Just noting that I have a similar (but different) proposal in #16739.