bidimensionales arreglos array ruby-on-rails arrays ruby

ruby on rails - arreglos - Cómo determinar si una matriz contiene todos los elementos de otra matriz



array ruby (6)

Dependiendo de cuán grandes sean sus matrices, podría considerar un algoritmo eficiente O (n log n)

def equal_a(a1, a2) a1sorted = a1.sort a2sorted = a2.sort return false if a1.length != a2.length 0.upto(a1.length - 1) do |i| return false if a1sorted[i] != a2sorted[i] end end

La ordenación cuesta O (n log n) y la comprobación de cada par cuesta O (n), por lo que este algoritmo es O (n log n). Los otros algoritmos no pueden ser más rápidos (asintóticamente) utilizando matrices no ordenadas.

Dado:

a1 = [5, 1, 6, 14, 2, 8]

Me gustaría determinar si contiene todos los elementos de:

a2 = [2, 6, 15]

En este caso, el resultado es false .

¿Hay algún método incorporado de Ruby / Rails para identificar dicha inclusión de matriz?

Una forma de implementar esto es:

a2.index{ |x| !a1.include?(x) }.nil?

¿Hay una forma mejor y más legible?


Esto se puede lograr haciendo

(a2 & a1) == a2

Esto crea la intersección de ambas matrices, devolviendo todos los elementos de a2 que también están en a1 . Si el resultado es el mismo que a2 , puede estar seguro de que tiene todos los elementos incluidos en a1 .

Este enfoque solo funciona si todos los elementos en a2 son diferentes entre sí en primer lugar. Si hay dobles, este enfoque falla. El de Tempos todavía funciona entonces, por lo que recomiendo sinceramente su enfoque (también es probable que sea más rápido).


Puedes aplicar un parche de mono a la clase Array:

class Array def contains_all?(ary) ary.uniq.all? { |x| count(x) >= ary.count(x) } end end

prueba

irb(main):131:0> %w[a b c c].contains_all? %w[a b c] => true irb(main):132:0> %w[a b c c].contains_all? %w[a b c c] => true irb(main):133:0> %w[a b c c].contains_all? %w[a b c c c] => false irb(main):134:0> %w[a b c c].contains_all? %w[a] => true irb(main):135:0> %w[a b c c].contains_all? %w[x] => false irb(main):136:0> %w[a b c c].contains_all? %w[] => true irb(main):137:0> %w[a b c d].contains_all? %w[d c h] => false irb(main):138:0> %w[a b c d].contains_all? %w[d b c] => true

Por supuesto, el método se puede escribir como un método estándar solo, por ejemplo

def contains_all?(a,b) b.uniq.all? { |x| a.count(x) >= b.count(x) } end

y puedes invocarlo como

contains_all?(%w[a b c c], %w[c c c])

De hecho, después del perfilado, la siguiente versión es mucho más rápida y el código es más corto.

def contains_all?(a,b) b.all? { |x| a.count(x) >= b.count(x) } end


Si no hay elementos duplicados o si no te importan, puedes usar la clase Set :

a1 = Set.new [5, 1, 6, 14, 2, 8] a2 = Set.new [2, 6, 15] a1.subset?(a2) => false

Detrás de las escenas esto usa

all? { |o| set.include?(o) }


Tal vez esto es más fácil de leer:

a2.all? { |e| a1.include?(e) }

También puede usar la intersección de matriz:

(a1 & a2).size == a1.size

Tenga en cuenta que el size se usa aquí solo para la velocidad, también puede hacerlo (más lento):

(a1 & a2) == a1

Pero creo que el primero es más legible. Estos 3 son rubí simple (no rieles).


a = [5, 1, 6, 14, 2, 8] b = [2, 6, 15] a - b => [5, 1, 14, 8] b - a => [15] (b - a).empty? => false