2012-02-01 22 views
33

Devo verificare se due array contengono gli stessi dati in qualsiasi ordine. Utilizzando il metodo immaginario compare, vorrei fare:Confronto di due array in Ruby

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 

ho usato arr1.sort == arr2.sort, che sembra funzionare, ma c'è un modo migliore di fare questo?

risposta

25

L'ordinamento degli array prima del confronto è O (n log n). Inoltre, come sottolinea Victor, ti troverai nei guai se la matrice contiene oggetti non ordinabili. È più veloce confrontare gli istogrammi, O (n).

Troverete Enumerable#frequency in sfaccettature, ma implementare da soli, che è abbastanza semplice, se si preferisce evitare di aggiungere più dipendenze:

require 'facets' 
[1, 2, 1].frequency == [2, 1, 1].frequency 
#=> true 
+0

Grazie. Questa è l'unica soluzione che restituisce true solo per i primi 'arr1' e' arr2', quando confronti ciascuno di questi array: 'arr1 = [1,2,3,5,4]; arr2 = [3,4,2,1,5]; arr3 = [3,4,2,1,5,5]; arr4 = [1,2,3,5,4,4] '- Non sono sicuro se sarei sempre preso la briga di installare la gemma delle faccette, ma se lo sto usando comunque per qualcosa, questo sembra un metodo molto migliore. – SimonMayer

+1

Oltre a n log n 'sort' non funziona bene con tipi diversi, ad es. se ci sono 'nil's. La frequenza dovrebbe funzionare bene, buona idea. –

+0

Un'implementazione semplice di "frequenza" è con inject: class Array; frequenza di def; self.inject (Hash.new (0)) {| p, v | p [v] + = 1; p} fine; fine –

3

si può effettivamente implementare questo metodo #compare dal monkey patching classe Array in questo modo:

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

Tenete a mente che la scimmia patching è raramente considerata una buona pratica e si dovrebbe essere prudenti quando lo si utilizza.

Probabilmente c'è un modo migliore per farlo, ma è quello che mi è venuto in mente. Spero che sia d'aiuto!

+1

Grazie. Sapevo di poterlo fare. Sono più preoccupato di ciò che sarebbe "confrontare". – SimonMayer

+0

In realtà questo è il modo più veloce, anche rispetto al confronto dei set ('Set.new (array1) == Set.new (array2)') –

29

Il modo più semplice è quello di utilizzare le intersezioni:

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

Quindi la dichiarazione

@array2 & @array1 == @array2 

sarà true. Questa è la soluzione migliore se si desidera verificare se array1 contiene array2 o il contrario (che è diverso). Inoltre, non stai armeggiando con i tuoi array o modificando l'ordine degli articoli. Puoi anche confrontare la lunghezza di entrambi gli array se vuoi che siano di dimensioni identiche.

E 'anche il modo più veloce per farlo (correggetemi se sbaglio)

+8

Quindi, per una risposta completa, 'a.size == b.size e a & b == a' implementati come un metodo' compare (a, b) 'o una patch di scimmia. –

+0

'arr1 & arr3 == arr1' restituisce true, che non voglio. Il suggerimento di Mark è un miglioramento, ma vale la pena notare che non riesce a gestire molto bene i valori duplicati. Vedi esempio 'arr4 = [1,2,3,5,4,4]; p arr4.size == arr3.size e arr4 & arr3 == arr4', che restituisce true – SimonMayer

+0

@SimonMayer Mi permetto di dissentire. 'arr3 = [3,4,2,1,5,5]; arr4 = [1,2,3,5,4,4]; p arr4 & arr3 == arr4' # => ** false ** –

12

Se si sa che non ci sono ripetizioni in una qualsiasi delle matrici (vale a dire, tutti gli elementi sono unici o si don' t care), utilizzando set è semplice e leggibile:

Set.new(array1) == Set.new(array2) 
0

Ecco una versione che funziona su array non ordinabile

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) 
2

Il modo più elegante che ho trovato:

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 
+0

funziona anche con gli oggetti –

+5

codificati in questo modo, ma questo codice ha un'eccezione grave. [1,1,1,1] - [1,2] = [], che non è lo stesso. – Canna

+0

vero. grazie per aver segnalato questo –

2

È possibile aprire la classe array e definire un metodo come questo.

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

arr1.compare(arr2) 
irb => true 

O utilizzare semplicemente

arr1.to_set == arr2.to_set 
irb => true 
1

sono in ritardo, ma in questo caso con ruby ​​2.3.x:

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

utilizzare:

a - b == b - a && a.length == b.length 
=> true 

a - c == c - a && a.length == c.length 
=> false 

Quando voglio basta confrontare due matrici avere stesso contenuto, io uso:

a - b == b - a 
=> true 

a - c == c - a 
=> true 

Ci dispiace per il mio cattivo inglese!

+1

No. Prova matrici [1,2,2] e [1,1,2] –

+0

Grazie! Ho capito che la mia risposta è sbagliata. – hoangdd