2011-02-04 13 views
21

Estoy buscando para ver si una matriz tiene uno o más valores dentro de ella. Por ejemplo, algo así:¿Cómo se comprueba si los valores de una matriz incluyen uno o más valores?

[1,2,3,4,5,6].include?([4,1]) # => true 
[4,1,6,2].include?([4,1]) # => true 
[3,4,7].include?([4,1]) # => false 

Por supuesto, el "incluir?" método solo puede verificar un valor. ¿Hay algún método para verificar valores múltiples?

+0

¿Qué versión de Ruby se han utilizado aquí? Me estoy poniendo falso en cada ocasión. irb (main): 006: 0> [1,2,3,4,5,6] .include? ([4,1]) => false irb (main): 007: 0> [4, 1,6,2] .include? ([4,1]) => falso irb (main): 008: 0> [3,4,7] .include? ([4,1]) – ram

Respuesta

15

EDIT: Apoyo Mark Thomas' solución alternativa que utiliza el núcleo Setclass.

Si bien mi solución responde de forma más estricta a la pregunta de cómo hacer esto con las matrices, sjsc puede beneficiarse al revisar su propio caso y explorar la opción de usar conjuntos en su lugar.

Hay muchos métodos válidos para usar matrices (mantener el orden, permitiendo duplicados), para lo cual aún es suficiente, pero si ninguno de ellos está involucrado, sjsc podría beneficiarse de usar Set en lugar de Array, y esa medida, la solución de Mark es semánticamente superior.


No conozco ningún método de biblioteca que lo haga, pero no sería demasiado difícil escribir su propia función.

class Array 
    def subset?(a) 
    (self - a).length == 0 
    end 
end 

estoy seguro de que hay maneras computacionalmente más eficientes para lograr esto, pero esto se debe hacer lo que usted está buscando.

La intersección de matrices funciona y básicamente equivale a lo mismo.

class Array 
    def subset?(a) 
    (self & a).length == length 
    end 
end 

Optimización en este nivel no va a ayudar a cuestiones demasiado, pero lo que no quiero hacer es empezar a comparar matrices múltiples veces:

class Array 
    # don't do this 
    def subset?(a) 
    (self & a) == a 
    end 
end 
+0

Método impresionante. Gracias Steven! – sjsc

+1

No es necesario reinventar la rueda, cuando la clase Set está en la biblioteca central. Ver mi respuesta –

+0

Gracias, Mark. Es mi error que no hice mi investigación antes de responder la pregunta para buscar una clase "set". –

3

¿Qué pasa con [1,2,3,4,5,6].include?(4) and [1,2,3,4,5,6].include?(1)?

+0

Gracias Schwartzie . ¿Sabes si hay una forma más eficiente de hacerlo? – sjsc

+0

@StevenXu obtiene mi voto por elegancia. – Schwartzie

+0

Realmente aprecio tratar de ayudar a Schwartzie. Gracias de nuevo. – sjsc

57
>> [1,2,3,4,5,6] & [4,1] 
=> [1, 4] 
>> [1,2,3,4,5,6] & [7,9] 
=> [] 
>> 
+1

Gran enfoque kurami. ¡Gracias! – sjsc

+0

Eso es genial. Gracias. –

+0

Solo haciendo una nota que esto significa. Ampersand es el operador set-intersection, que devuelve una colección de elementos comunes en ambas matrices. –

1

@kurumi está en lo cierto, pero pensé que me gustaría añadir que a veces utilizo esta pequeña extensión cuando yo sólo quiero un subconjunto de una matriz (por lo general las claves hash sin embargo):

class Hash 
    # Usage { :a => 1, :b => 2, :c => 3}.except(:a) -> { :b => 2, :c => 3} 
    def except(*keys) 
    self.reject { |k,v| 
     keys.include? k 
    } 
    end 

    # Usage { :a => 1, :b => 2, :c => 3}.only(:a) -> {:a => 1} 
    def only(*keys) 
    self.dup.reject { |k,v| 
     !keys.include? k 
    } 
    end 
end 

class Array 
    def except(*values) 
    self.reject { |v| 
     values.include? v 
    } 
    end 

    def only(*values) 
    self.reject { |v| 
     !values.include? v 
    } 
    end 
end 
+0

Esto va a ser extremadamente útil. ¡Realmente aprecio que digas eso! Muchas gracias scragz. – sjsc

+0

Array.except existe en Ruby estándar como - Array.only existe en Ruby estándar como & Ver: [1,2,3] - [1,3] => [3] y [1,2,3] & [1,2] => [1,2] –

25

esta es una operación de conjunto. Set está en la biblioteca estándar.

require 'set' 

a = Set[1,2,3,4,5,6] 
b = Set[4,1] 

b.subset? a 
#=> true 
+0

Funcionó muy bien para mí, gracias. Solo quería mencionar ese conjunto [1] .proper_subset? Set [1] devolverá falso. Entonces, si no puede garantizar que tratará con valores múltiples, ¿configuró [1] .subset? El conjunto [1] devolverá verdadero, al igual que el ejemplo anterior que devuelve verdadero. – johnnyx25

+0

tenga en cuenta que esto es bastante lento si está convirtiendo una matriz en un conjunto, en comparación con (a & b) .size == b.size que parece ser el más rápido – mrbrdo

+0

@mrbrdo Si bien eso es cierto, a veces realmente desea un Establecer (por ejemplo, con deduplicación automática) en cuyo caso una matriz no debería haberse construido para empezar. En mi opinión, las clases de la biblioteca estándar se pasan por alto con demasiada frecuencia. –

6

Una extensión rápida y sucia para @ enfoque de Schwartzie:

larger_array = [1,2,3,4,5,6] 
smaller_array = [4,1] 
smaller_array.all? {|smaller_array_item| larger_array.include?(smaller_array_item)} 
2

Mi conclusión es que el método La resta es generalmente agradable, pero reales Conjunto objetos están ardiendo rápido, ya que son claramente optimizado para este tipo de computación.

El uso de este script: https://gist.github.com/1996001

Tengo estos resultados de referencia (en Ruby 1.9.2p290):

SUBTRACTION 
- subset 
    0.180000 0.000000 0.180000 ( 0.189767) 
- partial subset 
    0.170000 0.000000 0.170000 ( 0.178700) 
- non subset 
    0.180000 0.000000 0.180000 ( 0.177606) 

INTERSECTION 
- subset 
    0.190000 0.000000 0.190000 ( 0.194149) 
- partial subset 
    0.190000 0.000000 0.190000 ( 0.191253) 
- non subset 
    0.190000 0.000000 0.190000 ( 0.195798) 

SET 
- subset 
    0.050000 0.000000 0.050000 ( 0.048634) 
- partial subset 
    0.040000 0.000000 0.040000 ( 0.045927) 
- non subset 
    0.050000 0.010000 0.060000 ( 0.052925) 

que considero bastante sorprendente, sobre todo si se echa un vistazo a la fuente:

# File 'lib/set.rb', line 204 

def subset?(set) 
    set.is_a?(Set) or raise ArgumentError, "value must be a set" 
    return false if set.size < size 
    all? { |o| set.include?(o) } 
end 

a través de: http://rubydoc.info/stdlib/set/1.9.2/Set#subset%3F-instance_method

+0

sí, pero la conversión de matriz a configuración no es muy rápida, por lo general, tendría que tener eso en cuenta – mrbrdo

+0

Quizás. Y aunque no convierto la matriz en un conjunto para cada iteración, la convierto una vez para cada prueba de conjunto, por lo que es completamente eclipsada por la velocidad de las operaciones de conjunto en ese nivel. Si va a realizar una cantidad tan grande de operaciones de Ajuste, entonces debe hacer lo mismo, convertir a Establecer una vez (o comenzar con un Conjunto) y luego realizar sus operaciones repetitivas, en lugar de convertirlas constantemente entre un Conjunto y otro. y Array. –

+0

Estoy de acuerdo en eso. – mrbrdo

4

Base en Kurumi y la sugerencia de spyle, aquí están mi prueba:

([1,2,3,4,5,6] & [4,1]). Any? # => verdadero

Sin embargo, .any? a su vez, cualquier objeto en true

([1,2,3,4,5,6] & [6,7]). alguna? # => True

Así que creo que aquí puede haber uno que funcione:

([1,2,3,4,5,6] & [6,7]) .length == [6,7] .length # => false

(bigger_array & smaller_array) .length == smaller_array.length

2

me gusta la respuesta de Kurumi, pero sólo para tirar uno más por ahí:

>> set1 = [1,2,3,4,5,6] 
[ 
    [0] 1, 
    [1] 2, 
    [2] 3, 
    [3] 4, 
    [4] 5, 
    [5] 6 
] 
>> set2 = [4,1] 
[ 
    [0] 4, 
    [1] 1 
] 
>> set1.any?{ |num| set2.include?(num) } 
true 
>> set2 = [8,9] 
[ 
    [0] 8, 
    [1] 9 
] 
>> set1.any?{ |num| set2.include?(num) } 
false 
0

simple y mejor manera:

([4,1] - [1,2,3,4,5 , 6]). ¿Vacío? # => verdadero

([4,1] - [4,1,6,2]) ¿vacío? # => verdadero

([4,1] - [3,4,7]) ¿vacío? # => False

0

Esto comprobará si existe un elemento en una matriz:

students = ["jim", "bob", "sally"] 
teachers = ["mrs. jones", "mrs. sharpe", "mrs. ray"] 

puts "what's your name ?" 
answer = gets.chomp 

if answer.include?(students.to_s) 
    puts "you are a student" 

elsif 
    puts "you are a teacher" 

end 
Cuestiones relacionadas