2010-11-12 8 views
7

grep Das ist, was ich stattdessen getan:Ruby-Äquivalent -v

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

Ich fühle mich wie dies ein wenig sperrig, aber ich habe nichts, dass gebaut gefunden würde mich lassen ändern zu my_array.grepv /regex/ { ... }

Gibt es eine solche Funktion?

+1

Ich glaube nicht. Sie könnten jedoch selbst einen erstellen! – rogerdpack

+0

'grep_v' ist eine Methode zum Aufzählen seit Ruby 2.3 – steenslag

Antwort

0

Versuchen Array#collect!

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

EDIT: Sorry, dann würden Sie anrufen müssen Array#compact nach. Zumindest würde das den zweiten Block eliminieren. Aber es ist mehr physikalischer Code. Es hängt davon ab, wie viel "Zeug" du tust.

1

können Sie tun:

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

aber wirklich ist es schwer, prägnante und selbsterklärend zu sein. Es könnte geschrieben werden mit grep(/.../) mit einigen negativen Lookahead-Muster, aber dann denke ich, es wird schwieriger, die Gesamtaktion zu verstehen, weil das Muster selbst schwerer zu verstehen ist.

3

Ich glaube nicht, dass es so etwas eingebaut, aber es ist einfach genug, hinzuzufügen:

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

Beachten Sie, dass Pars verwenden, um die Regex benötigen, wenn Sie diese Funktion aufrufen, sonst bekommen Sie ein Syntaxfehler:

myarray.grepv(/regex/) { ... } 
0

Sie müssen lediglich das Ergebnis des regexp Spiels negieren.

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 
4

Wie wäre es damit?

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

Ich habe bewusst ein dup enthalten, um sicherzustellen, dass alle von ihnen zurückgegeben werden.

0

Vielen Dank für Ihre Kommentare. Am Ende habe ich es auf diese Weise:

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 

nicht sicher, ob das der beste Weg ist, weil ich mit Ruby-bin nur am Anfang. Es ist hier ein wenig länger als die Lösungen anderer Leute, aber ich mag es, weil es ziemlich analog zur grep -Option von Enumerable ist - es funktioniert mit allem, was mit dem ==5, genau wie grep, zusammenhängt und liefert die gefundenen Elemente, wenn ein Block vorhanden war gegeben, und beide Wege gibt ein Array von denen, die nicht übereinstimmen.

Ich fügte den or to_s Teil hinzu, so dass alle Integer, die zum Beispiel im Array eingestreut waren, mit dem gleichen Regex verglichen werden konnten, obwohl ich mir vorstellen könnte, dass das manchmal etwas anhebt.

7

Sie wissen, wie Symbol#to_proc hilft bei der Verkettung? Sie können das gleiche mit regulären Ausdrücken tun:

class Regexp 
    def to_proc 
    Proc.new {|string| string =~ self} 
    end 
end 

["Ruby", "perl", "Perl", "PERL"].reject(&/perl/i) 
=> ["Ruby"] 

Aber Sie sollten wahrscheinlich nicht.Grep einfach nicht mit regulären Ausdrücken arbeiten - Sie können es wie folgt aus

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

verwenden können, und wenn Sie grep wollte -v, dass, würden Sie Class#to_proc implementieren müssen, was falsch klingt.

+0

diese Antwort fängt den minimalistischen Geist von Rubin ein - zu schade, es gibt keinen einfachen Weg, es auf diese Weise für alle Verhaltensweisen von grep zu machen – jdsumsion

4

Wie steht es mit dem Invertieren der Regex?

["ab", "ac", "bd"].grep(/^[^a]/) # => ["bd"] 
0

Hier ist ein weiterer Schuss auf ihn, mit einer Prise bltxd ‚s und Hsiu‘ s Antworten und hoffentlich so viel von dem Geist der ursprünglichen grep wie möglich (auch wenn es wortreich) beibehalten:

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 

Wenn Sie einen Block liefern, dann ist alles faul wie Sie erwarten würden. Wenn Sie keinen Block bereitstellen, gibt es einen kleinen doppelten Code. Ich wünschte wirklich, dass Andrew Grimm 's Antwort im allgemeinen Fall anwendete.

>> (%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 keinem Fall tun Sie O(n^2) für Artikel Vergleich zahlen, wie Sie es im schlimmsten Fall, wenn Sie Array Subtraktion tun.