2012-06-28 4 views
14

Demo (Ich gehe davon aus [3] führen):Wie mache ich vernünftige "Set-Differenz" in Ruby?

[1,2] - [1,2,3] => [] # Hmm 
[1,2,3] - [1,2] => [3] # I see 

a = [1,2].to_set => #<Set: {1, 2}> 
b = [1,2,3].to_set => #<Set: {1, 2, 3}> 
a - b    => #<Set: {}> WTF! 

Und:

[1,2,9] - [1,2,3] => [9] # Hmm. Would like [[9],[3]] 

Wie soll man einen echten Satz Differenz unabhängig von der Reihenfolge der Eingänge erfüllen?

Ps. Nebenbei, ich muss dies für zwei 2000-Element-Arrays tun. Normalerweise wird Array # 1 weniger Elemente als Array # 2 haben, dies ist jedoch nicht garantiert.

Antwort

49

Die - operator auf zwei Arrays angewendet a und b gibt die relative complement von b in a (Elemente, die in a sind aber nicht in b).

Was Sie suchen, ist die symmetric difference von zwei Sätzen (die Vereinigung der beiden relativen Ergänzungen zwischen den beiden). Dadurch wird der Trick:

a = [1, 2, 9] 
b = [1, 2, 3] 
a - b | b - a   # => [3, 9] 

Wenn Sie auf Set Objekte arbeiten, können Sie die überladene ^ operator verwenden:

c = Set[1, 2, 9] 
d = Set[1, 2, 3] 
c^d     # => #<Set: {3, 9}> 

Für zusätzlichen Spaß, können Sie auch die relative Komplement des intersection finden konnten in die union der beiden Sätze:

(a | b) - (a & b) # => #<Set: {3, 9}> 
+1

+1, nette Antwort. Ich habe Array #^zu meiner [Erweiterungsbibliothek] hinzugefügt (http://rubydoc.info/gems/shenanigans/1.0.4/Array#%5E-instance_method), es ist nicht immer notwendig, Sätze zu durchlaufen. –