Elemente während des Iterierens sicher aus einer Array-Tabelle entfernen
Diese Frage ist ähnlich Wie kann ich sicher Durchlaufen eine lua-Tabelle, während die Tasten werden entfernt aber deutlich anders.
Zusammenfassung
Gegeben ein Lua-array (Tabelle mit Schlüssel und sequentiell Ganzzahlen ab 1
), was ist der beste Weg, um eine Iteration durch das array und löschen Sie die Einträge, wie Sie gesehen werden?
Real World " - Beispiel
Ich habe ein array mit Zeitstempel versehene Einträge, die in ein Lua-array-Tabelle. Einträge werden immer an das Ende des Arrays (mit table.insert
).
local timestampedEvents = {}
function addEvent( data )
table.insert( timestampedEvents, {getCurrentTime(),data} )
end
Ich muss gelegentlich laufen durch diese Tabelle (in der Reihenfolge) und Prozess-und-löschen bestimmter Einträge:
function processEventsBefore( timestamp )
for i,stamp in ipairs( timestampedEvents ) do
if stamp[1] <= timestamp then
processEventData( stamp[2] )
table.remove( timestampedEvents, i )
end
end
end
Leider ist der code oben erwähnten Ansatz bricht die iteration, überspringt einige Einträge. Gibt es eine bessere (weniger eingeben, aber immer noch sichere) Weg, dies zu tun, als manuell gehen die Indizes:
function processEventsBefore( timestamp )
local i = 1
while i <= #timestampedEvents do -- warning: do not cache the table length
local stamp = timestampedEvents[i]
if stamp[1] <= timestamp then
processEventData( stamp[2] )
table.remove( timestampedEvents, i )
else
i = i + 1
end
end
end
InformationsquelleAutor der Frage Phrogz | 2012-09-12
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verwenden Sie einfach
table.remove
. Allerdings, wenn Sie die Iteration von vorne nach hinten, beim entfernen des Elements N, das nächste element der iteration (N+1) verschoben wird, nach unten in die position. Wenn Sie erhöhen Ihre iteration (variabel, wie ipairs tut), Sie werden überspringen, dass element. Es gibt zwei Möglichkeiten, damit umzugehen.Verwendung in diesem Beispiel Daten:
Können wir entfernen
input
Elemente während der iteration durch:Durchlaufen von hinten nach vorne.
Steuerung der loop-variable manuell, so können wir überspringen Inkrementieren, wenn das entfernen eines Elements:
Für nicht-array-Tabellen, die Sie Durchlaufen mit
next
oderpairs
(die implementiert wird, in Bezug aufnext
) und legen Sie Artikel, die Sie wollen, entfernt zunil
.InformationsquelleAutor der Antwort Mud
Ich möchte vermeiden
table.remove
und Durchlaufen das array einmal setzen die unerwünschten Einträge zunil
dann Durchlaufen Sie das array wieder verdichten, wenn nötig.Hier der code, den ich im Auge habe, am Beispiel von Mud ' s Antwort:
InformationsquelleAutor der Antwort lhf
Versuchen, diese Funktion:
Es nicht
table.remove
, so sollte esO(N)
Komplexität. Sie bewegen könnte, dieremove
Funktion in die for-generator entfernen Sie die Notwendigkeit für eine upvalue, aber das würde bedeuten, dass eine neue closure für jedes element... und es ist nicht eine praktische Frage.Beispiel:
Seien Sie vorsichtig, nicht zu verwenden
break
(oder anderweitig zu beenden, vorzeitig aus der Schleife), wie es verlassen werden Sie das array mitnil
Elemente.Wenn Sie wollen
break
bedeutet "abort" (wie in, nichts ist entfernt), Sie könnten dies tun:Dies hat den Vorteil, dass Sie in der Lage zu stornieren, wird die gesamte Schleife keine Elemente entfernt werden, sowie die option zum überspringen über Elemente, die bereits als markiert "entfernt werden". Der Nachteil ist der Aufwand für eine neue Tabelle.
Ich hoffe, dass diese hilfreich für Sie sind.
InformationsquelleAutor der Antwort Deco
Könnten Sie überlegen, ein Priorität anstelle eines sortierten Arrays.
Eine priority-queue wird effizient kompakt selbst, wie Sie entfernen Sie die Einträge in der Reihenfolge.
Beispiel für eine priority queue-Implementierung finden Sie auf dieser mailing-Liste-thread: http://lua-users.org/lists/lua-l/2007-07/msg00482.html
InformationsquelleAutor der Antwort finnw
Ich auch empfohlen, vor der Verwendung die Tabelle.entfernen Sie aus performance-Gründen (das kann mehr oder weniger relevant für Ihre speziellen Fall).
Hier ist, was diese Art von Schleife in der Regel sieht aus wie bei mir:
Beachten Sie, dass dies ändert die Reihenfolge der Elemente im array.
Wenn Sie möchten, beibehalten der Reihenfolge der Elemente können Sie dann die Tabelle.entfernen und ich mache es so:
InformationsquelleAutor der Antwort Srekel
Mir fällt auf, dass—für meinen speziellen Fall, wo ich immer nur shift-Einträge von vorne in der Warteschlange—ich kann dies weit mehr einfach über:
Werde ich jedoch nicht akzeptieren dies als die Antwort, weil es nicht behandeln den Allgemeinen Fall von Iteration über ein array und entfernen zufällige Elemente aus der Mitte, während Sie weiterhin zu Durchlaufen.
InformationsquelleAutor der Antwort Phrogz
Können Sie einen Funktor zu prüfen, für die Elemente, die entfernt werden müssen. Der zusätzliche Gewinn ist, dass es abgeschlossen ist in O(n), weil es keine Tabelle.entfernen
Verwendung:
In Ihrem Fall:
InformationsquelleAutor der Antwort Luc Bloom