2013-11-25 8 views
12

Ich habe über ein folgendes Problem zu denken - es gibt zwei Arrays, und ich brauche Elemente nicht üblich, dass sie beide, zum Beispiel zu finden:Rubin - Finden Element nicht gemeinsam für zwei Arrays

a = [1,2,3,4] 
b = [1,2,4] 

Und die erwartete Antwort ist [3].

Komplexität
a.select { |elem| !b.include?(elem) } 

Aber es gibt mir O(N ** 2) Zeit:

ich so tun es Bisher habe. Ich bin sicher, es kann schneller erfolgen;)

Außerdem habe ich darüber nachgedacht, es irgendwie wie diese bekommen (eine Methode gegenüber & verwendet, die gemeinsamen Elemente von 2 Arrays gibt):

a !& b #=> doesn't work of course 

Eine andere Möglichkeit könnte sein, zwei Arrays hinzuzufügen und das einzigartige Element mit etwas ähnliches Verfahren wie uniq zu finden, so dass:

[1,1,2,2,3,4,4].some_method #=> would return 3 
+3

'(a-b) | (ba) # => [3] 'Siehe http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-2D und beachte, dass es nicht kommutativ ist, dh generell' ab ! = ba' – iamnotmaynard

+1

Das sollte sein: (ab) | (b-a) –

+0

@ShawnBalestracci Richtig du bist. Ich hatte es sogar richtig in meine Testkonsole geschrieben, aber es falsch umgeschrieben. – iamnotmaynard

Antwort

15

Die einfachste (in Bezug auf nur die Arrays bereits an Ort und Stelle und Lager Array Methoden, sowieso) Lösung ist die union der differences:

a = [1,2,3,4] 
b = [1,2,4] 
(a-b) | (b-a) 
=> [3] 

Dies kann oder nicht als O(n**2) besser sein kann. Es gibt andere Optionen, die wahrscheinlich eine bessere Leistung bringen (siehe andere Antworten/Kommentare).

Edit: Hier ist eine schnelle Implementierung des sort-and-iterate-Ansatzes (dies setzt voraus, dass kein Array wiederholte Elemente hat; andernfalls muss es geändert werden, je nachdem, welches Verhalten in diesem Fall gewünscht ist). Wenn jemand einen kürzeren Weg dazu finden könnte, wäre ich interessiert. Der begrenzende Faktor ist die verwendete Art. Ich gehe davon aus, dass Ruby eine Art Quicksort verwendet, so dass die Komplexität O(n log n) mit einem möglichen Worst-Case von O(n**2); Wenn die Arrays bereits sortiert sind, können natürlich die beiden Aufrufe von sort entfernt werden und es wird in O(n) ausgeführt.

def diff a, b 
    a = a.sort 
    b = b.sort 
    result = [] 
    bi = 0 
    ai = 0 
    while (ai < a.size && bi < b.size) 
    if a[ai] == b[bi] 
     ai += 1 
     bi += 1 
    elsif a[ai]<b[bi] 
     result << a[ai] 
     ai += 1 
    else 
     result << b[bi] 
     bi += 1 
    end 
    end 
    result += a[ai, a.size-ai] if ai<a.size 
    result += b[bi, b.size-bi] if bi<b.size 
    result 
end 
+0

Vereinigung des Unterschieds! Dank dafür! Unterstrich verwenden: 'Ergebnis = _.union (_. Unterschied (a, b), _.difference (b, a));' – BuffMcBigHuge

10
a = [1, 2, 3] 
b = [2, 3, 4] 
a + b - (a & b) 
# => [1, 4] 
+0

Welche ist vorzuziehen? Dies oder die akzeptierte Lösung? – Donato

+0

Diese Lösung ist aus Sicht der Speicherbereinigung besser (Sie können weniger Wert für ** total_allocated_object ** mit deaktiviertem GC sehen). – Anatoly

14

Wie @iamnotmaynard in der festgestellt Kommentare, das ist traditionell eine gesetzte Operation (die symmetrische Differenz genannt). Rubys Set Klasse umfasst diese Operation, so dass die meisten idiomatische Weise auszudrücken es mit einem Satz wäre:

Set.new(a)^b 

Das sollte O (n) Leistung (da einen Test der Zugehörigkeit konstant Zeit) geben.

0

Die Lösung für Array Divergenzen ist wie:

a = [1, 2, 3] 
b = [2, 3, 4] 
(a - b) | (b - a) 
# => [1, 4] 

Sie auch einen Blog-Post über Array coherences lesen kann