web-dev-qa-db-fra.com

Comment déterminer si un tableau contient tous les éléments d'un autre tableau

Donné:

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

Je voudrais déterminer s'il contient tous les éléments de:

a2 = [2, 6, 15]

Dans ce cas, le résultat est false.

Existe-t-il des méthodes Ruby/Rails intégrées pour identifier une telle inclusion de tableau?

Une façon d'implémenter ceci est:

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

Y a-t-il une meilleure façon, plus lisible?

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

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

b - a
=> [15]

(b - a).empty?
=> false
289
Geo

C'est peut-être plus facile à lire:

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

Vous pouvez également utiliser l'intersection de tableau:

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

Notez que size est utilisé ici juste pour la vitesse, vous pouvez aussi faire (plus lentement):

(a1 & a2) == a1

Mais je suppose que le premier est plus lisible. Ces 3 sont simples Ruby (pas Rails).

71
Pablo Fernandez

Ceci peut être réalisé en faisant

(a2 & a1) == a2

Cela crée l'intersection des deux tableaux, renvoyant tous les éléments de a2 qui sont aussi dans a1. Si le résultat est identique à a2, vous pouvez être sûr que tous les éléments sont inclus dans a1.

Cette approche ne fonctionne que si tous les éléments de a2 sont différents les uns des autres en premier lieu. S'il y a des doublons, cette approche échoue. Celui de Tempos fonctionne toujours alors, donc je recommande vivement son approche (aussi, il est probablement plus rapide).

53
Holger Just

S'il n'y a pas d'éléments en double ou si vous ne les aimez pas, vous pouvez utiliser la classe Set :

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

En coulisse, cela utilise

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

Vous pouvez monkey-patcher la classe Array:

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

tester

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

Bien sûr, la méthode peut être écrite en tant que méthode standard, par exemple

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

et vous pouvez l'invoquer comme

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

En effet, après le profilage, la version suivante est beaucoup plus rapide et le code est plus court.

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

La plupart des réponses basées sur (a1 - a2) ou (a1 et a2) ne fonctionneraient pas s'il y avait des éléments en double dans l'un des tableaux. Je suis arrivé ici en cherchant un moyen de voir si toutes les lettres d'un mot (fractionnées en un tableau) faisaient partie d'un ensemble de lettres (pour scrabble par exemple). Aucune de ces réponses n'a fonctionné, mais celle-ci fait:

def contains_all?(a1, a2)
  try = a1.chars.all? do |letter|
    a1.count(letter) <= a2.count(letter)
  end
  return try
end
0
Charles Breton

En fonction de la taille de vos tableaux, vous pourriez envisager un algorithme efficace 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

Trier les coûts O (n log n) et vérifier chaque paire coûte O(n)), donc cet algorithme est O (n log n). Les autres algorithmes ne peuvent pas être plus rapides (asymptotiquement) en utilisant des tableaux non triés.

0
ayckoster