108 votes

Vérifier si deux tableaux ont le même contenu (dans n'importe quel ordre)

J'utilise Ruby 1.8.6 avec Rails 1.2.3, et je dois déterminer si deux tableaux ont les mêmes éléments, qu'ils soient ou non dans le même ordre. Il est garanti que l'un des tableaux ne contient pas de doublons (l'autre pourrait en contenir, auquel cas la réponse est non).

Ma première pensée a été

require 'set'
a.to_set == b.to_set

mais je me demandais s'il existait une manière plus efficace ou idiomatique de le faire.

165voto

Mori Points 10767

Cela ne nécessite pas de conversion pour être fixé :

a.sort == b.sort

43voto

Pour deux tableaux A et B : A et B ont le même contenu si : (A-B).blank? and (B-A).blank?

ou vous pouvez juste vérifier pour : ((A-B) + (B-A)).blank?

De plus, comme suggéré par @cort3z, cette solution fonctionne également pour les tableaux polymorphes, à savoir

 A = [1 , "string", [1,2,3]]
 B = [[1,2,3] , "string", 1]
 (A-B).blank? and (B-A).blank? => true
 # while A.uniq.sort == B.uniq.sort will throw error `ArgumentError: comparison of Fixnum with String failed` 

:::::::::: : EDIT :::::::::::: :

Comme suggéré dans les commentaires, la solution ci-dessus échoue pour les doublons, bien que selon la question, ce n'est même pas nécessaire puisque le demandeur n'est pas intéressé par les doublons (il convertit ses tableaux en set avant de vérifier et cela masque les doublons et même si vous regardez la réponse acceptée, il utilise un opérateur .uniq avant de vérifier et cela aussi masque les doublons). Mais si les doublons vous intéressent, il suffit d'ajouter une vérification du nombre pour résoudre le problème (comme dans la question, un seul tableau peut contenir des doublons). Donc la solution finale sera : A.size == B.size and ((A-B) + (B-A)).blank?

38voto

SRack Points 3562

Ruby 2.6+

Ruby's a présenté difference en 2.6.

Cela donne une solution très rapide et très lisible ici, comme suit :

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

a.difference(b).any?
# => false
a.difference(b.reverse).any?
# => false

a = [1, 2, 3, 4, 5, 6]
b = [1, 2, 3]
a.difference(b).any?
# => true

Cependant, l'inverse n'est pas vrai :

a = [1, 2, 3]
b = [1, 2, 3, 4, 5, 6]
a.difference(b).any?
# => false

Cela signifie que pour obtenir la différence dans les deux sens, il est nécessaire de courir :

a.difference(b).any? || b.difference(a).any?

Exécution des tests de référence :

a = Array.new(1000) { rand(100) }
b = Array.new(1000) { rand(100) }

Benchmark.ips do |x|
  x.report('sort')   { a.sort == b.sort }  
  x.report('sort!')  { a.sort! == b.sort! }  
  x.report('to_set') { a.to_set == b.to_set }  
  x.report('minus')  { ((a - b) + (b - a)).empty? }  
  x.report('difference') { a.difference(b).any? }
  x.report('difference two way') { a.difference(b).any? || b.difference(a).any? }
end

                sort     10.175k (± 6.2%) i/s -     50.778k in   5.015112s
               sort!     10.513k (± 6.8%) i/s -     53.212k in   5.089106s
              to_set      4.953k (± 8.8%) i/s -     24.570k in   5.037770s
               minus     15.290k (± 6.6%) i/s -     77.520k in   5.096902s
          difference     25.481k (± 7.9%) i/s -    126.600k in   5.004916s
  difference two way     12.652k (± 8.3%) i/s -     63.232k in   5.038155s

Ce que je retiens, c'est que difference est un excellent choix pour un différentiel unidirectionnel.

Si vous devez vérifier dans les deux sens, c'est un équilibre entre les performances et la lisibilité. Pour moi, la lisibilité l'emporte, mais c'est une décision à prendre au cas par cas.

J'espère que cela aidera quelqu'un !

26voto

Morozov Points 909

Comparaisons de vitesse

require 'benchmark/ips'
require 'set'

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

Benchmark.ips do |x|
  x.report('sort')   { a.sort == b.sort }  
  x.report('sort!')  { a.sort! == b.sort! }  
  x.report('to_set') { a.to_set == b.to_set }  
  x.report('minus')  { ((a - b) + (b - a)).empty? }  
end  

Warming up --------------------------------------
            sort    88.338k i/100ms
           sort!   118.207k i/100ms
          to_set    19.339k i/100ms
           minus    67.971k i/100ms
Calculating -------------------------------------
            sort      1.062M (± 0.9%) i/s -      5.389M in   5.075109s
           sort!      1.542M (± 1.2%) i/s -      7.802M in   5.061364s
          to_set    200.302k (± 2.1%) i/s -      1.006M in   5.022793s
           minus    783.106k (± 1.5%) i/s -      3.942M in   5.035311s

18voto

Jared Beck Points 4975

Lorsque les éléments de a y b son Comparable ,

a.sort == b.sort

Correction de la réponse de @mori basée sur le commentaire de @steenslag

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X