2011-01-02 13 views
7

Ho bisogno di unire elementi ripetuti consecutivi in ​​una matrice, in modo tale cheCome si uniscono gli elementi ripetuti consecutivi in ​​un array?

[1, 2, 2, 3, 1] 

diventa

[1, 2, 3, 1] 

#uniq non funziona per questo scopo. Perché? Perché #uniq produrrà questo:

[1, 2, 3] 
+0

perché pretende molto uniq lavorare? stai usando uniq o uniq !? – sethvargo

+0

Vedere anche la domanda duplicata _ [Eliminare duplicati consecutivi di elementi di elenco] (http://stackoverflow.com/q/5544701/405017) _. – Phrogz

risposta

7
def remove_consecutive_duplicates(xs) 
    [xs.first] + xs.each_cons(2).select do |x,y| 
    x != y 
    end.map(&:last) 
end 

remove_consecutive_duplicates([1, 2, 2, 3, 1]) 
#=> [1,2,3,1] 

Ciò restituisce un nuovo array come uniq fa e lavora a O(n) tempo. risposta

+0

Seriamente, ben fatto. 'each_cons (2) .select' infatti! – Phrogz

+0

Non sapevo di * each_cons *, bello! –

-3

fa !uniq non funziona per quello che stai facendo?

http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_array.html

+1

-1.) Disse nella sua risposta che non funziona e 2.) il suo uniq! no! uniq – sethvargo

+1

'! uniq' non è un nome di metodo valido in ruby. 'uniq!' fa la stessa cosa di uniq', ma sul posto. Quindi non è quello che l'OP vuole (dal momento che vuole solo rimuovere i duplicati * consecutivi). – sepp2k

+0

Non ha notato il requisito duplicato "consecutivo". OP potrebbe volere esplicitamente affermarlo. –

3

di sepp2k è già accettata, ma qui ci sono alcune alternative:

# Because I love me some monkeypatching 
class Array 
    def remove_consecutive_duplicates_2 
    # Because no solution is complete without inject 
    inject([]){ |r,o| r << o unless r.last==o; r } 
    end 

    def remove_consecutive_duplicates_3 
    # O(2n) 
    map.with_index{ |o,i| o if i==0 || self[i-1]!=o }.compact 
    end 

    def remove_consecutive_duplicates_4 
    # Truly O(n) 
    result = [] 
    last = nil 
    each do |o| 
     result << o unless last==o 
     last = o 
    end 
    result 
    end 
end 

E anche se la prestazione è non tutto, qui ci sono alcuni benchmark:

Rehearsal -------------------------------------------- 
sepp2k     2.740000   0.010000   2.750000 ( 2.734665) 
Phrogz_2   1.410000   0.000000   1.410000 ( 1.420978) 
Phrogz_3   1.520000   0.020000   1.540000 ( 1.533197) 
Phrogz_4   1.000000   0.000000   1.000000 ( 0.997460) 
----------------------------------- total: 6.700000sec 

               user     system      total        real 
sepp2k     2.780000   0.000000   2.780000 ( 2.782354) 
Phrogz_2   1.450000   0.000000   1.450000 ( 1.440868) 
Phrogz_3   1.530000   0.020000   1.550000 ( 1.539190) 
Phrogz_4   1.020000   0.000000   1.020000 ( 1.025331) 

benchmark eseguito su rimozione dei duplicati da orig = (0..1000).map{ rand(5) } 10.000 volte.

10

C'è un'astrazione nel nucleo che fa più o meno il lavoro, Enumerable#chunk:

xs = [1, 2, 2, 3, 3, 3, 1] 
xs.chunk { |x| x }.map(&:first) 
#=> [1, 2, 3, 1] 
+1

Molto più breve, più pulito e più efficiente della risposta accettata. – Sim

+1

Questo non funzionerà correttamente se l'array ha valori nulli, dato che farà sì che questi valori vengano scartati. – Reck

+0

Buon punto. Non avevo idea che "chunk" avesse questi valori speciali. Se l'input può avere quei valori speciali, dovrebbero essere tutti avvolti. – tokland

Problemi correlati