Subtrahieren eines Arrays von einem anderen in Ruby

81

Ich habe zwei Arrays von Aufgaben - erstellt und zugewiesen. Ich möchte alle zugewiesenen Aufgaben aus dem Array der erstellten Aufgaben entfernen. Hier ist mein funktionierender, aber unordentlicher Code:

    @assigned_tasks = @user.assigned_tasks
    @created_tasks = @user.created_tasks

    #Do not show created tasks assigned to self
    @created_not_doing_tasks = Array.new
    @created_tasks.each do |task|
        unless @assigned_tasks.include?(task)
            @created_not_doing_tasks << task
        end
    end

Ich bin sicher, es gibt einen besseren Weg. Was ist es? Vielen Dank :-)

Doktororange
quelle
Ich wette, unter der Haube macht die Antwort genau das, was Sie dort codiert haben.
Baash05

Antworten:

174

Sie können Arrays in Ruby subtrahieren:

[1,2,3,4,5] - [1,3,4]  #=> [2,5]

ary - other_ary → new_ary Array-Differenz

Gibt ein neues Array zurück, das eine Kopie des ursprünglichen Arrays ist, und entfernt alle Elemente, die auch in other_ary angezeigt werden. Die Reihenfolge bleibt vom ursprünglichen Array erhalten.

Es vergleicht Elemente mit ihrem Hash und Gl. Methoden für die Effizienz.

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]

Wenn Sie ein setartiges Verhalten benötigen, lesen Sie die Bibliotheksklasse Set.

Siehe die Array- Dokumentation.

Hobodave
quelle
2
Arg. Großer Gesichtspalmenmoment für mich. Aus irgendeinem Grund dachte ich, dass das mit Objekten nicht funktionieren würde. Hat gut funktioniert - danke!
Doctororange
28
Testen Sie dies vorsichtig im IRB, zum Beispiel: [5, 5, 5, 5] - [5, 5] = [] ... die Subtraktion entfernt die eindeutigen Elemente im Array.
Hagope
9
Beachten Sie auch, dass dies nicht funktioniert : [1,2]-[1,2,3] => []. Aber [1,2,3]-[1,2] => [3]. Argh.
Zabba
17
Wenn Sie in Subtraktion denken, dann machen diese letzten "Fallstricke" tatsächlich Sinn. Um zu subtrahieren etwas , das Sie nicht für einen fragen diff ... Sie fordern Y von X zu subtrahieren ... wenn Y etwas nicht einmal in X hat dann das Ergebnis ist eine Art ‚undefined‘, also die zusätzliche Y-Element wouldn werden nicht in das X-Ergebnis aufgenommen.
Bane
2
Insbesondere Array#-ist ein Satz Unterschied. Es ist eher eine Umkehrung einer Mengenvereinigung als Array#|eine Array#+Verkettung (überhaupt keine Mengenoperation!).
ymbirtt
9

Die obige Lösung

a - b

löscht alle Instanzen von Elementen im Array baus dem Array a.

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]

In einigen Fällen möchten Sie das Ergebnis haben [1, 2, 3, 3, 5]. Das heißt, Sie möchten nicht alle Duplikate löschen, sondern nur die Elemente einzeln.

Sie könnten dies erreichen, indem Sie

class Array
  def delete_elements_in(ary)
    ary.each do |x|
      if index = index(x)
        delete_at(index)
      end
    end
  end
end

Prüfung

irb(main):198:0> a = [ 1, 1, 2, 2, 3, 3, 4, 5 ]
=> [1, 1, 2, 2, 3, 3, 4, 5]
irb(main):199:0> b = [ 1, 2, 4 ]
=> [1, 2, 4]
irb(main):200:0> a.delete_elements_in(b)
=> [1, 2, 4]
irb(main):201:0> a
=> [1, 2, 3, 3, 5]

Der Code funktioniert auch dann, wenn die beiden Arrays nicht sortiert sind. Im Beispiel sind die Arrays sortiert, dies ist jedoch nicht erforderlich.

Zack Xu
quelle
delete_elements_inist in Ruby nicht verfügbar (Ruby 2.6.3p62)
qaisjp
@qaisjp, weil es vom Autor definiert wird. Du sollst es auch definieren. Sehen Sie sich den Code über dem Testcode an.
ismailarilik
Anscheinend kann ich nicht lesen. Danke, @ismailarilik.
Qaisjp