Vérifiez 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. L’un des tableaux est garanti pour ne pas contenir de doublons (l’autre pourrait, auquel cas la réponse est non).

Ma première pensée était

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

mais je me demandais s’il y avait une façon plus efficace ou idiomatique de le faire.

Cela ne nécessite pas de conversion pour définir:

 a.sort == b.sort 

pour deux tableaux A et B: A et B ont le même contenu si: (AB).blank? and (BA).blank? (AB).blank? and (BA).blank?

ou vous pouvez simplement vérifier: ((AB) + (BA)).blank?

Comme suggéré par @ cort3z, cette solution fonctionne également pour les tableaux polymorphes

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

::::::::::: MODIFIER :::::::::::::

Comme suggéré dans les commentaires, la solution ci-dessus échoue pour les doublons.Bien que selon la question qui n’est même pas requirejse puisque le demandeur ne s’intéresse pas aux doublons (il convertit ses tableaux pour les vérifier et masque les doublons et même la réponse acceptée, il utilise un opérateur .uniq avant de vérifier et cela masque aussi les doublons.). Mais encore, si les doublons vous intéressent, le simple fait d’append une vérification du compte corrigera la même chose (selon la question, un seul tableau peut contenir des doublons). La solution finale sera donc: A.size == B.size and ((AB) + (BA)).blank?

Lorsque les éléments de a et b sont Comparable ,

 a.sort == b.sort 

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

Vitesse Comparsions

 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.338ki/100ms sort! 118.207ki/100ms to_set 19.339ki/100ms minus 67.971ki/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 

Si vous attendez [:a, :b] != [:a, :a, :b] to_set [:a, :b] != [:a, :a, :b] to_set [:a, :b] != [:a, :a, :b] to_set ne fonctionne pas. Vous pouvez utiliser la fréquence à la place:

 class Array def frequency p = Hash.new(0) each{ |v| p[v] += 1 } p end end [:a, :b].frequency == [:a, :a, :b].frequency #=> false [:a, :b].frequency == [:b, :a].frequency #=> true 

Si vous savez que les tableaux sont de même longueur et qu’aucun tableau ne contient de doublons, cela fonctionne également:

 ( array1 & array2 ) == array1 

Explication: L’opérateur & dans ce cas renvoie une copie de a1 sans aucun élément introuvable dans a2, qui est identique à l’original a si les deux tableaux ont le même contenu sans doublons.

Analyis: Étant donné que l’ordre est inchangé, je suppose que cela est implémenté comme une double itération de manière cohérente O(n*n) , notamment pire pour les grands tableaux que a1.sort == a2.sort qui devrait fonctionner dans le pire des cas O(n*logn) .

Une approche consiste à itérer le tableau sans doublons

 # assume array a has no duplicates and you want to compare to b !a.map { |n| b.include?(n) }.include?(false) 

Cela retourne un tableau de trues. Si un faux apparaît, alors les externes include? reviendra vrai. Vous devez donc inverser le tout pour déterminer s’il s’agit d’une correspondance.