2011-01-02 11 views
7

Ich brauche aufeinanderfolgenden sich wiederholenden Elementen in einem Array zu verschmelzen, so dassWie können Sie aufeinander folgende sich wiederholende Elemente in einem Array zusammenführen?

[1, 2, 2, 3, 1] 

[1, 2, 3, 1] 

#uniq wird für diesen Zweck nicht funktioniert. Warum? Da #uniq wird diese produzieren:

[1, 2, 3] 
+0

warum tut uniq arbeiten? verwendest du uniq oder uniq !? – sethvargo

+0

Siehe auch die doppelte Frage _ [Fortlaufende Duplikate von Listenelementen entfernen] (http://stackoverflow.com/q/5544701/405017) _. – Phrogz

Antwort

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] 

Das ist wie uniq ein neues Array zurückgibt tut und in O(n) Zeit arbeitet.

+0

Ernsthaft, gut gemacht. 'each_cons (2) .select' in der Tat! – Phrogz

+0

Wusste nicht von * each_cons *, nette! –

-3

hat !uniq nicht arbeiten für das, was Sie tun?

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

+1

-1 1.) er sagte in seiner Antwort, dass es nicht funktioniert und 2.) seine uniq! nicht! uniq – sethvargo

+1

'! uniq' ist kein gültiger Methodenname in Ruby. 'uniq!' macht dasselbe wie 'uniq', aber in-place. Es ist also nicht das, was das OP will (da er nur * aufeinanderfolgende * Duplikate entfernen will). – sepp2k

+0

Die "konsekutive" doppelte Anforderung wurde nicht beachtet. OP könnte dies ausdrücklich erklären wollen. –

3

Antwort des sepp2k bereits akzeptiert, aber hier sind einige Alternativen:

# 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 

Und obwohl die Leistung nicht alles ist, hier sind einige Benchmarks:

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) 

Benchmarks auf die Beseitigung von Duplikaten führen von orig = (0..1000).map{ rand(5) } 10.000 mal.

10

Es gibt eine Abstraktion im Kern, dass so ziemlich die Arbeit erledigt, Enumerable#chunk:

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

Weit kürzer, sauberer und effizienter als die angenommene Antwort. – Sim

+1

Dies funktioniert nicht korrekt, wenn das Array keine Werte enthält, da diese Werte verworfen werden. – Reck

+0

Guter Punkt. Ich hatte keine Ahnung, dass "Chunk" diese besonderen Werte hatte. Wenn die Eingabe diese speziellen Werte haben kann, sollten sie alle umschlossen sein. – tokland

Verwandte Themen