Project

General

Profile

Actions

Feature #9602

closed

Logic with `Enumerable#grep`

Added by sawa (Tsuyoshi Sawada) almost 11 years ago. Updated about 5 years ago.

Status:
Feedback
Target version:
-
[ruby-core:96047]

Description

Enumerable#grep is useful to filter things:

[nil, {}, [], 1, :foo, "foo"].grep(String)
# => ["foo"]
  1. 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 like Enumerable#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 after when in case condition:

     [nil, {}, [], 1, :foo, "foo"].grep(String, Symbol, Array)
     # => [[], :foo, "foo"]
    
  2. Also, it often happens that I want the negation of grep. Perhaps, Enumerable#grepv (grepv comes from grep -v) can be implemented as negation of Enumerable#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

select-to-accept-args.patch (2.62 KB) select-to-accept-args.patch srawlins (Sam Rawlins), 03/07/2014 04:18 AM

Related issues 1 (0 open1 closed)

Related to Ruby master - Feature #11049: Enumerable#grep_v (inversed grep)Closedmatz (Yukihiro Matsumoto)Actions

Updated by matz (Yukihiro Matsumoto) almost 11 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) almost 11 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) almost 11 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) almost 11 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) almost 11 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) almost 11 years ago

I've updated my patch with Array#select, nobu's break suggestion, and documentation and tests:

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.

Actions #8

Updated by akr (Akira Tanaka) over 9 years ago

Updated by msnm (Masahiro Nomoto) about 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.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0