2010-11-12 20 views
7

Questo è quello che ho fatto, invece:Rubino equivalente a grep -v

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

mi sento come questo è un po 'ingombrante, ma non ho trovato nulla di costruito in che mi permetteva di cambiarlo a my_array.grepv /regex/ { ... }

Esiste una tale funzione?

+1

Non credo. potresti crearne uno tu, però! – rogerdpack

+0

'grep_v' è un metodo enumerabile da Ruby 2.3 – steenslag

risposta

0

Prova utilizzando Array#collect!

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

EDIT: Siamo spiacenti, allora si dovrebbe chiamare Array#compact dopo. Almeno questo eliminerebbe il secondo blocco. Ma è più codice fisico. Dipende da quanta "roba" fai.

1

Si può fare:

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

ma in realtà è difficile essere più conciso e di auto-documentazione. Potrebbe essere scritto usando grep(/.../) con un modello di lookahead negativo, ma poi penso che sia più difficile comprendere l'azione complessiva perché il pattern stesso è più difficile da capire.

3

Non credo ci sia nulla di built-in come questo, ma è abbastanza semplice per aggiungere:

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

Si noti che è necessario utilizzare parentesi intorno alla regex quando si chiama questa funzione, altrimenti si ottiene un errore di sintassi:

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

È sufficiente annullare il risultato della corrispondenza regexp.

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

Che ne dici di questo?

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

Ho incluso intenzionalmente un dup per assicurarsi che tutti vengano restituiti.

0

Grazie a tutti per i vostri commenti. Alla fine, l'ho fatto in questo modo:

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 

Non sono sicuro se questo è il modo migliore perché ho appena iniziato con Ruby. È un po 'più lungo delle soluzioni di altre persone qui, ma mi piace perché è abbastanza analogo all'opzione grep di Enumerable - funziona con tutto ciò che può gestire il ===, proprio come grep, e produce gli oggetti che trova se un blocco era dato, e in entrambi i casi restituisce una matrice di quelli che non corrispondono.

Ho aggiunto la parte or to_s in modo che qualsiasi numero intero, ad esempio, intervallato nell'array potesse essere abbinato alla stessa espressione regolare, anche se potrei immaginare che questo a volte potrebbe causare problemi.

7

Sai come Symbol#to_proc ti aiuta con il concatenamento? Puoi fare lo stesso con le espressioni regolari:

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

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

Ma probabilmente non si dovrebbe.Grep non funziona solo con le espressioni regolari - si può utilizzare come il seguente

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

e se si voleva a grep -v che, si sarebbe necessario implementare Class#to_proc, che suona male.

+0

questa risposta cattura lo spirito minimalista del rubino - peccato non ci sia un modo semplice per farlo funzionare in questo modo per tutti i comportamenti di grep – jdsumsion

4

Che dire di invertire la regex?

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

Ecco un altro colpo a lui, con una spolverata di bltxd 's e Hsiu' risposte s, e, auspicabilmente, mantenendo come gran parte del spirito dell'originale grep possibile (anche se è prolisso):

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 

Se fornisci un blocco, allora tutto è pigro come ti aspetteresti. Se non fornisci un blocco, c'è un piccolo codice duplicato. Mi auguro davvero che la risposta di Andrew Grimm sia applicata nel caso generale.

>> (%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 nessuno dei due casi si fa a pagare fino a O(n^2) per il confronto voce, come si farebbe nel caso peggiore se si fa matrice sottrazione.