2012-03-07 15 views
6

Dire che ho una matrice che assomiglia:Come posso rilevare i valori duplicati all'interno di un array in Ruby?

a = [cat, dog, cat, mouse, rat, dog, cat] 

Come faccio a scorrere questo, e fare qualcosa con i duplicati - per esempio dì cancellarli?

In altre parole, se avessi fatto a.each do |i|, come valuto un [0], contro un [1], un [2], un [3] ... e poi quando trovo quello che voglio, dì un [2] in questo caso ha il primo duplicato, poi lo spingo in una pila o lo rimuovo o qualcosa del genere.

So come valutare le chiavi, rispetto ai valori ... ma come si valutano i valori gli uni contro gli altri all'interno dello stesso array?

Grazie.

risposta

11

È possibile creare un hash per immagazzinare il numero di volte in cui ogni elemento si ripete tornerà. Quindi iterando su array solo una volta.

h = Hash.new(0) 
['a','b','b','c'].each{ |e| h[e] += 1 } 

dovrebbe portare

{"a"=>1, "b"=>2, "c"=>1} 
+1

Perché non 'h = Hash.new (0)' e 'h [e] + = 1'? –

+0

Materia della sintassi. È a discrezione dei programmatori. – ch4nd4n

+0

Questo è in realtà quello che stavo cercando di fare .... ma ... non riuscivo a capire come usare il 'nil? 'E incrementare i metodi proprio come questo. Grazie! – marcamillion

1

Una soluzione semplice è quello di eseguire un doppio loop:

a.each_with_index do |a1, idx1| 
    a.each_with_index do |a2, idx2| 
    next if idx1 >= idx2 # Don't compare element to itself 
         # and don't repeat comparisons already made 

    # do something with a pair of elements (a1, a2) 
    end 
end 

Se si desidera solo per eliminare i duplicati, c'è un metodo: Array#uniq.

+0

Pensato a questo, ma sembra così disordinato. C'è una soluzione più elegante, "ruby-ish"? – marcamillion

+0

Per eliminare i duplicati, c'è un metodo. Per confrontare tutti gli elementi tra loro, c'è un doppio ciclo. Personalmente non vedo nessun casino. È semplice codice che legge bene. –

+0

Sergio questo metodo è inefficiente perché stai facendo paragoni inutili che sono stati fatti in passato. Il secondo ciclo interno dovrebbe avviarlo in seguito (più avanti nell'array) su ciascun ciclo. – MMM

1

Utilizzare a.uniq! per rimuovere i duplicati.

anche checkout the ruby-doc.org dove è possibile trovare maggiori informazioni sui metodi di classe di ruby.

+0

compact rimuove nils dall'array. Come è utile in questa situazione? –

+0

concordato. Guardato i documenti e non funziona. – marcamillion

+0

scusate per scrivere uniq. :) – lesce

3

Prova questo:

class Array 
    def find_dups 
     uniq.map {|v| (self - [v]).size < (self.size - 1) ? v : nil}.compact 
    end 
end 

a = ['cat', 'dog', 'cat', 'mouse', 'rat', 'dog', 'cat'] 

print a - a.find_dups # Removes duplicates 

find_dups elementi che hanno i duplicati

5

Questo funziona in modo efficiente ed è piuttosto semplice:

require 'set' 

visited = Set.new 
array.each do |element| 
    if visited.include?(element) 
    # duplicated item 
    else 
    # first appearance 
    visited << element 
    end 
end 
1

Prova questa:

 
array.inject({}){|h, e| h[e] = h[e].to_i + 1; h} 
0

Questo stamperà tutti i duplicati di un array :

array.inject(Hash.new(0)) { |hash,val| 
    hash[val] += 1; 
    hash 
}.each_pair { |val,count| 
    puts "#{val} -> #{count}" if count > 1 
} 
0

Se si desidera eliminare solo i duplicati, la cosa più semplice da fare è prendere l'array e fare array dell'array &. Utilizzare l'operatore &.

Se si desidera sapere quali sono quelle ripetizioni, è sufficiente confrontare l'array con l'array &.

0

Se la matrice è ordinabile, qualcosa di simile restituirà solo i duplicati.

array.sort.each_cons(2).select {|p| p[0] == p[1] }.map &:first 

ordina l'array, allora lo mappa di coppie consecutive di elementi, seleziona coppie che sono uguali, mappe di elementi.

0

Il modo migliore per farlo è confrontarlo con una versione unica di se stesso. Se è lo stesso, non ha duplicati, se non esistono duplicati.

unique_array = original_array.uniq 

ottenere una versione unica della matrice

if original_array == unique_array then return true else return false 

confrontarlo con l'array originale.

Semplice!

Problemi correlati