Ruby equivalent grep -v

Here is what I did instead:

my_array.reject { |elem| elem =~ /regex/ }.each { ... } 

It seems to me that this is a little cumbersome, but I did not find anything built-in that would allow me to change it to my_array.grepv /regex/ { ... }

Is there such a function?

+7
ruby regex grep
source share
10 answers

Do you know how Symbol#to_proc helps with chaining? You can do the same with regular expressions:

 class Regexp def to_proc Proc.new {|string| string =~ self} end end ["Ruby", "perl", "Perl", "PERL"].reject(&/perl/i) => ["Ruby"] 

But you probably shouldn't. Grep doesn't just work with regular expressions - you can use it as shown below.

 [1,2, "three", 4].grep(Fixnum) 

and if you want to use grep -v you will have to implement Class#to_proc , which sounds wrong.

+7
source share

Ruby 2.3 implements the Enumerable#grep_v , which is exactly right for you.

https://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-grep_v

+6
source share

How about this?

 arr = ["abc", "def", "aaa", "def"]
 arr - arr.grep (/ a /) # => ["def", "def"]

I intentionally included a duplicate to make sure that they are all returned.

+4
source share

What about regular expression inversion?

 ["ab", "ac", "bd"].grep(/^[^a]/) # => ["bd"] 
+4
source share

I do not believe that there is something built in, but it is simple enough to add:

 class Array def grepv(regex, &block) self.reject { |elem| elem =~ regex }.each(&block) end end 

Note that you need to use parens around the regular expression when calling this function, otherwise you will get a syntax error:

 myarray.grepv(/regex/) { ... } 
+3
source share

You can do:

 my_array.reject{|e| e[/regex/]}.each { ... } 

but it’s actually difficult to be more concise and self-documenting. It could be written using grep(/.../) with some negative feedback pattern, but then it seems harder for me to understand the general action, because the template itself is harder to understand.

+1
source share

Try using Array#collect!

 my_array.collect! do |elem| if elem =~ /regex/ # do stuff elem end end 

EDIT: Sorry, you will need to call Array#compact after. At the very least, this will eliminate the second block. But this is more physical code. It depends on how much you do.

0
source share

You just need to deny the regex match result.

 Enumerable.module_eval do def grepv regexp if block_given? self.each do |item| yield item if item !~ regexp end else self.find_all do |item| item !~ regexp end end end end 
0
source share

Thank you all for your comments. In the end, I did it as follows:

 module Enumerable def grepv(condition) non_matches = [] self.each do |item| unless condition === item or condition === item.to_s non_matches.push(item) yield item if block_given? end end return non_matches end end 

Not sure if this is the best way because I'm just starting out with Ruby. This is a bit longer than other solutions for people, but I like it because it is quite similar to the Enumerable grep parameter - it works with everything that can handle ===, like grep, and it gives the elements it finds, if the block and in any case returns an array of those that do not match.

I added the or to_s part so that any integers, for example, interspersed in an array, can be matched with the same regular expression, although I could assume that this can sometimes hurt things.

0
source share

Here's another shot at her, with a spray of bltxd and Hsuu responding, and hopefully retains as much of the spirit of the original grep as possible (even if it is verbose):

 module Enumerable def grepv(condition) if block_given? each do |item| yield item if not condition === item end else inject([]) do |memo, item| memo << item if not condition === item memo end end end end 

If you put a block, then everything will be lazy, as you expected. If you do not supply a block, there is a small duplicate of the code. I really want Andrew Grimm to answer in the general case.

 >> (%w(1 2 3) + [4]).cycle(3).grepv(Fixnum) => ["1", "2", "3", "1", "2", "3", "1", "2", "3"] >> (%w(1 2 3) + [4]).cycle(3).grepv(/[12]/) => ["3", 4, "3", 4, "3", 4] 

In any case, you do not pay up to O(n^2) for comparing the elements, as in the worst case, if you subtract the subtraction of the array.

0
source share

All Articles