2010-11-12 9 views
7

Esto es lo que he estado haciendo en su lugar:equivalente a grep -v Rubí

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

siento que esto es un poco difícil de manejar, pero no he encontrado nada construido en el que me permitiera cambiarlo a my_array.grepv /regex/ { ... }

¿Existe tal función?

+1

No lo creo. ¡podrías crear uno tú mismo! – rogerdpack

+0

'grep_v' es un método enumerable ya que Ruby 2.3 – steenslag

Respuesta

0

Trate de usar Array#collect!

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

EDIT: Lo sentimos, entonces usted tendría que llamar Array#compact después. Al menos eso eliminaría el segundo bloque. Pero es más código físico. Depende de la cantidad de "cosas" que hagas.

1

Usted puede hacer:

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

pero realmente es difícil ser más conciso y auto-documentado. Podría escribirse usando grep(/.../) con algún patrón de búsqueda negativa, pero luego creo que se hace más difícil comprender la acción general porque el patrón en sí es más difícil de entender.

3

No creo que haya nada incorporada como este, pero es lo suficientemente simple para agregar:

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

Tenga en cuenta que es necesario utilizar parens torno a la expresión regular cuando se llama a esta función, de lo contrario se obtiene un error de sintaxis:

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

sólo hay que anular el resultado de la coincidencia de expresiones regulares.

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

¿Qué le parece esto?

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

Incluí deliberadamente un dup para asegurarme de que se devolvieran todos.

0

Gracias a todos por sus comentarios. Al final, lo hice de esta manera:

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 

No estoy seguro si esa es la mejor manera porque sólo estoy Primeros pasos con Ruby. Aquí es un poco más largo que las soluciones de otras personas, pero me gusta porque es bastante análogo a la opción grep de Enumerable: funciona con cualquier elemento que pueda manejar el ===, al igual que grep, y arroja los elementos que encuentra si un bloque era dado, y de cualquier manera devuelve una matriz de aquellos que no coinciden.

Agregué la parte or to_s para que cualquier número entero, por ejemplo, intercalado en la matriz pudiera coincidir con la misma expresión regular, aunque podría imaginar que esto podría cambiar las cosas a veces.

7

¿Sabes cómo Symbol#to_proc ayuda con el encadenamiento? Puede hacer lo mismo con expresiones regulares:

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

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

Pero probablemente no debería.Grep no solo trabaja con expresiones regulares - se puede usar como el siguiente

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

y si quería a grep -v eso, se tendría que aplicar Class#to_proc, que suena mal.

+0

esta respuesta captura el espíritu minimalista de ruby ​​- lástima que no hay una manera fácil de hacerlo funcionar de esta manera para todos los comportamientos de grep – jdsumsion

4

¿Qué tal invertir la expresión regular?

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

Aquí hay otro tiro en él, con una rociada de bltxd 's y Hsiu' respuestas s, y es de esperar que conserva la mayor cantidad de espíritu del original grep como sea posible (incluso si es prolijo):

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 

Si proporciona un bloque, todo es flojo como cabría esperar. Si no proporciona un bloque, hay un pequeño código duplicado. Realmente deseo que la respuesta de Andrew Grimm se aplique en el caso general.

>> (%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] 

En ninguno de los casos hacen que paga hasta O(n^2) elemento de comparación, al igual que lo haría en el peor de los casos si lo hace matriz resta.

Cuestiones relacionadas