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?
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]
a - b
=> [5, 1, 14, 8]
b - a
=> [15]
(b - a).empty?
=> false
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).
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).
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) }
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
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
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.