web-dev-qa-db-fra.com

Comparaison de deux tableaux ignorant l'ordre des éléments dans Ruby

Je dois vérifier si deux tableaux contiennent les mêmes données dans n'importe quel ordre. En utilisant la méthode imaginaire compare, je voudrais faire:

arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]

arr1.compare(arr2) #true    
arr1.compare(arr3) #false

J'ai utilisé arr1.sort == arr2.sort, ce qui semble fonctionner, mais existe-t-il une meilleure façon de procéder?

48
SimonMayer

Le tri des tableaux avant de les comparer est O (n log n). De plus, comme le souligne Victor, vous rencontrerez des problèmes si le tableau contient des objets non triables. Il est plus rapide de comparer les histogrammes, O (n).

Vous trouverez Enumerable # fréquence dans Facets, mais implémentez-le vous-même, ce qui est assez simple, si vous préférez éviter d'ajouter plus de dépendances:

require 'facets'
[1, 2, 1].frequency == [2, 1, 1].frequency 
#=> true
32
tokland

Le moyen le plus simple consiste à utiliser les intersections:

@array1 = [1,2,3,4,5]
@array2 = [2,3,4,5,1]

Donc, la déclaration

@array2 & @array1 == @array2

Sera true. C'est la meilleure solution si vous souhaitez vérifier si array1 contient array2 ou l'inverse (c'est différent). Vous ne jouez pas non plus avec vos tableaux ni ne changez l'ordre des articles. Vous pouvez également comparer la longueur des deux tableaux si vous souhaitez qu'ils soient de taille identique.

C'est aussi le moyen le plus rapide de le faire (corrigez-moi si je me trompe)

36
MMM

Si vous savez qu'il n'y a pas de répétitions dans aucun des tableaux (c'est-à-dire que tous les éléments sont uniques ou que vous ne vous souciez pas), l'utilisation d'ensembles est simple et lisible:

Set.new(array1) == Set.new(array2)
18
Gunchars

Vous pouvez réellement implémenter ce #compare méthode par patch de singe la classe Array comme ceci:

class Array
  def compare(other)
    sort == other.sort
  end
end

Gardez à l'esprit que le patch de singe est rarement considéré comme une bonne pratique et vous devez être prudent lorsque vous l'utilisez.

Il existe probablement une meilleure façon de procéder, mais c'est ce qui m'est venu à l'esprit. J'espère que ça aide!

6
Tomislav Dyulgerov

Vous pouvez ouvrir la classe array et définir une méthode comme celle-ci.

class Array
  def compare(comparate)
    to_set == comparate.to_set
  end
end

arr1.compare(arr2)
irb => true

OU utilisez simplement

arr1.to_set == arr2.to_set
irb => true
3
Datt

La manière la plus élégante que j'ai trouvée:

arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]


(arr1 - arr2).empty? 
=> true

(arr3 - arr2).empty?
=> false
3
Lukasz Muzyka

Voici une version qui fonctionnera sur des tableaux non triables

class Array
  def unordered_hash
    unless @_compare_o && @_compare_o == hash
      p = Hash.new(0)
      each{ |v| p[v] += 1 }
      @_compare_p = p.hash
      @_compare_o = hash
    end
    @_compare_p
  end
  def compare(b)
    unordered_hash == b.unordered_hash
  end
end

a = [ 1, 2, 3, 2, nil ]
b = [ nil, 2, 1, 3, 2 ]
puts a.compare(b)
0