Feature #18135
openIntroduce Enumerable#detect_only
Description
It can be important to get the only element for which a block returns true, and to assert that this is the only element as such. For example, this can be a very helpful sanity check when one is working with data that's outside of their control and is not perfectly understood. They may have a guess as to how to get a specific element matching some criteria, but if they used Enumerable#detect might be hiding the fact that they have written an incorrect block and that there's in fact more than one element that matches it. It could also be a parameter on Typically, I'd do it like this:
matches = array.select { |elem| some_method(elem) }
raise if matches.size != 0
match = matches.first
Here, it would be shortened to:
match = array.detect_only { |elem| some_method(elem) }
It could also be a parameter on Enumerable#detect instead of a separate method.
Updated by jeremyevans0 (Jeremy Evans) about 3 years ago
- Tracker changed from Bug to Feature
- Backport deleted (
2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN)
Updated by meisel (Michael Eisel) about 3 years ago
Also, another alternative could be Enumerable#take_only
, where it takes the only element from the enumerable or else fails. So instead of:
array.detect_only { |elem| some_method(elem) }
We'd have:
array.select { |elem| some_method(elem) }.take_only
Updated by duerst (Martin Dürst) about 3 years ago
meisel (Michael Eisel) wrote in #note-2:
Also, another alternative could be
Enumerable#take_only
, where it takes the only element from the enumerable or else fails. So instead of:array.detect_only { |elem| some_method(elem) }
We'd have:
array.select { |elem| some_method(elem) }.take_only
It's a good idea to separate things out, but this could be highly inefficient (checking and selecting lots of elements only to find out later that there's more than one).
Updated by mame (Yusuke Endoh) about 3 years ago
- Related to Feature #13683: Add strict Enumerable#single added
Updated by mame (Yusuke Endoh) about 3 years ago
Do you mean raise if matches.size != 1
instead of ... != 0
?
The idea of take_only
is already proposed in #13683.
Updated by meisel (Michael Eisel) about 3 years ago
Yes, I meant ... != 1
, thanks. And I think we can close this issue, and I'll add my thoughts to the issue that this dupes.