Cómo determinar si un array contiene todos los elementos de otro array


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 matrices?

Una forma de implementar esto es:

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

¿Hay una manera mejor, más legible?

Author: the Tin Man, 2011-09-12

6 answers

a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

a - b
=> [5, 1, 14, 8]

b - a
=> [15]

(b - a).empty?
=> false
 266
Author: Geo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-25 16:13:36

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

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

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

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

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

(a1 & a2) == a1

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

 63
Author: Pablo Fernandez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 12:42:39

Esto se puede lograr haciendo

(a2 & a1) == a2

Esto crea la intersección de ambos arrays, 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, así que recomiendo de todo corazón su enfoque (también es probablemente más rápido).

 49
Author: Holger Just,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-01 22:05:26

Si no hay elementos duplicados o no te importan, entonces 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 que utiliza

all? { |o| set.include?(o) }
 9
Author: Confusion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 17:22:35

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

Ordenar los costos O(n log n) y verificar 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) usando arrays sin clasificar.

 0
Author: ayckoster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 17:36:19

Usted puede monkey-parchear 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 de perfilar, 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
 0
Author: Zack Xu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-15 16:28:45