Feature #9602
closedLogic with `Enumerable#grep`
Description
Enumerable#grep
is useful to filter things:
[nil, {}, [], 1, :foo, "foo"].grep(String)
# => ["foo"]
-
Often, the condition cannot be expressed as a single object on which
===
is applied, but as a disjunction over===
applied to multiple objects. I would likeEnumerable#grep
to take arbitrary number of arguments, and when they are more than one, a logical disjunction applies, just as when there are multiple comma-separated objects afterwhen
incase
condition:[nil, {}, [], 1, :foo, "foo"].grep(String, Symbol, Array) # => [[], :foo, "foo"]
-
Also, it often happens that I want the negation of grep. Perhaps,
Enumerable#grepv
(grepv
comes fromgrep -v
) can be implemented as negation ofEnumerable#grep
, i.e., select elements for which===
returns false on any of the arguments:[nil, {}, [], 1, :foo, "foo"].grepv(String, Symbol, Array) # => [nil, {}, 1]
Files
Updated by matz (Yukihiro Matsumoto) over 10 years ago
- Status changed from Open to Feedback
- Assignee set to matz (Yukihiro Matsumoto)
I am afraid that proposed behavior is too far away from the original 'grep'.
We should use #select for more complex filtering.
Any opinion?
Matz.
Updated by srawlins (Sam Rawlins) over 10 years ago
+1 to Matz's idea. I think this would work like Enumerable#count
, taking *args
or a block, but not both:
%w{foo bar baz}.select #=> an Enumerator
%w{foo bar baz}.select {|e| e['b']} #=> an Array ["bar", "baz"]
%w{foo bar baz}.select(/b/) #=> an Array ["bar", "baz"]
%w{foo bar baz}.select(/f/, /z/) #=> an Array ["foo", "baz"]
%w{foo bar baz}.select(/b/) {|e| e['f']} # warns "given block not used", returns ["bar", "baz"]
I have a short patch for Enumerable#select on GitHub, and attached. This idea should be extended to Enumerable#reject, and Array's #select and #reject, and probably Array's #select! and #reject!, and maybe other classes that extend Enumerable, and override #select and #reject (like Struct#select).
If this patch is acceptable, I am happy to extend the patch for the other #select and #reject methods, and write tests.
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
Sam Rawlins wrote:
%w{foo bar baz}.select(/b/) {|e| e['f']} # warns "given block not used", returns ["bar", "baz"]
It should raise a "wrong number of arguments" exception, IMO.
+ for (j=0; j<RARRAY_LEN(ary); j++) { + if (RTEST(rb_funcall(RARRAY_AREF(ary, j), id_eqq, 1, i))) { + rb_ary_push(memo->u2.value, i);
It should break
after once matched.
Updated by srawlins (Sam Rawlins) over 10 years ago
Hi Nobu, I was just using the same warning from enum_count, enum_find_index, and enum_inject. But it could raise
if that is still desired. I'll fix with break
.
Updated by sawa (Tsuyoshi Sawada) over 10 years ago
Sam Rawlins wrote:
This idea should be extended to Enumerable#reject, and Array's #select and #reject, and probably Array's #select! and #reject!, and maybe other classes that extend Enumerable, and override #select and #reject (like Struct#select).
If this patch is acceptable, I am happy to extend the patch for the other #select and #reject methods, and write tests.
I agree on this feature. I think this what many people would want.
Updated by srawlins (Sam Rawlins) over 10 years ago
I've updated my patch with Array#select, nobu's break
suggestion, and documentation and tests:
- GitHub: https://github.com/srawlins/ruby/compare/select-to-accept-args
- patch file: https://github.com/srawlins/ruby/compare/select-to-accept-args.patch
If we want to go forward with this, I just need to do Enumerable#reject, Array#select!, Array#reject, Array#reject!, and I think Struct#select. I don't think this feature should be applied to Hash#select.
Updated by srawlins (Sam Rawlins) over 10 years ago
I've updated my patch some more with Enumerable#reject and Array#reject. (Array#reject was weird... I reabsorbed ary_reject()
into rb_ary_reject()
and left the only use of rb_ary_push_1()
intact. I think some of this code was very old.)
Updated code at GitHub: https://github.com/srawlins/ruby/compare/select-to-accept-args (as a patch)
All that remains is Array#select!, Array#reject!, and Struct#select.
Updated by akr (Akira Tanaka) over 9 years ago
- Related to Feature #11049: Enumerable#grep_v (inversed grep) added
Updated by msnm (Masahiro Nomoto) almost 5 years ago
I agree with sawa's opinion. Enumerable#grep
and other methods using ===
internally should accept more than one arguments, following when
conditions.
Yukihiro Matsumoto wrote:
We should use #select for more complex filtering.
#select
is highly versatile. I think it's good that there is a filter method that has the ability between (current) #grep
and #select
.