Der effizienteste Weg, um festzustellen, ob eine Lua-Tabelle leer ist (keine Einträge enthält)?


120

Was ist der effizienteste Weg, um festzustellen, ob eine Tabelle leer ist (dh derzeit weder Werte im Array-Stil noch Werte im Diktat-Stil enthält)?

Derzeit verwende ich next():

if not next(myTable) then
    -- Table is empty
end

Gibt es einen effizienteren Weg?

Hinweis: Der #Operator reicht hier nicht aus, da er nur mit den Werten im Array-Stil in der Tabelle arbeitet - daher #{test=2}ist er nicht zu unterscheiden, #{}da beide 0 zurückgeben. Beachten Sie auch, dass die Überprüfung, ob die Tabellenvariable ist nil, nicht ausreicht, da ich nicht suche Nullwerte, sondern Tabellen mit 0 Einträgen (dh {}).

Antworten:


149

Ihr Code ist effizient, aber falsch. (Überlegen Sie {[false]=0}.) Der richtige Code ist

if next(myTable) == nil then
   -- myTable is empty
end

Für maximale Effizienz möchten Sie nextan eine lokale Variable binden , z.

...
local next = next 
...
... if next(...) ...

1
Guter Punkt zur technischen Korrektheit; In den besonderen Fällen, in denen ich den Originalcode verwendet habe, falsewäre dies kein erwarteter Schlüssel, so dass er einwandfrei if notfunktioniert, aber ich werde es mir wahrscheinlich zur Gewohnheit machen, ihn nilstattdessen in Zukunft zu vergleichen, nur als gute Angewohnheit. Und ja, ich habe allgemeine Dienstprogrammfunktionen aus Geschwindigkeitsgründen an lokale Variablen gebunden. Vielen Dank für die Eingabe.
Amber

1
Es fällt mir schwer, der Unrichtigkeit zuzustimmen, wenn der Code wie beabsichtigt funktioniert
RD Alkire

4
Warum gewinnen wir dadurch an Geschwindigkeit local next?
Moberg

2
@Moberg Dies liegt daran, wie LUA mit seinem Namespace umgeht. Die sehr heruntergekommene Version ist, dass sie zuerst auf die lokalen Tische klettert. Wenn sich also eine local nextim aktuellen Block befindet, wird diese verwendet, dann auf den nächsten Block geklettert und wiederholt. Sobald die Einheimischen nicht mehr erreichbar sind, wird nur dann der globale Namespace verwendet. Dies ist eine heruntergekommene Version davon, aber am Ende bedeutet es definitiv den Unterschied in Bezug auf die Programmgeschwindigkeit.
ATaco

@Moberg Die weniger heruntergekommene Version im Kontext von Lua 5.2 & 5.3 ist, dass Nicht-Einheimische entweder Upvals oder _ENV-Lookups sind. Ein Upval muss eine zusätzliche Indirektionsebene durchlaufen, während eine _ENV-Suche eine Tabellensuche ist. Während ein Einheimischer ein Register in der VM ist
Demur Rumed

1

Eine Möglichkeit wäre, die Anzahl der Elemente mithilfe des metatierbaren Schlüssels "newindex" zu zählen. Wenn Sie etwas nicht nilzuweisen, erhöhen Sie den Zähler (der Zähler könnte auch in der Metatabelle leben) und beim Zuweisennil , dekrementieren Sie den Zähler, .

Das Testen auf eine leere Tabelle würde bedeuten, den Zähler mit 0 zu testen.

Hier ist ein Zeiger auf eine metatierbare Dokumentation

Ihre Lösung gefällt mir jedoch und ich kann ehrlich gesagt nicht davon ausgehen, dass meine Lösung insgesamt schneller ist.


5
Bei der ursprünglichen Frage geht es nicht nur darum, "Array" -Einträge zu zählen.
lhf

3
Der Vorschlag von 0x6 ist nicht spezifisch für Einträge im Array-Stil (newindex funktioniert sowohl für numerische als auch für nicht numerische Indizes). Das Hauptproblem wäre jedoch die Erkennung, wann nilzugewiesen wird, da __newindex nicht ausgelöst wird, wenn der Schlüssel bereits in der Tabelle vorhanden ist.
Amber

3
Damit dieser Trick funktioniert, müsste die Metatabelle beides implementieren __indexund __newindexdie tatsächlichen Daten in einer Schattentabelle speichern und die reale Tabelle leer lassen, damit __indexsie überhaupt aufgerufen wird. Wenn ich laut nachdenke, vermute ich, dass sich die erhöhten Kosten für jede einzelne Suche nicht lohnen können.
RBerteig

0

Dies ist wahrscheinlich, was Sie wollten:

function table.empty (self)
    for _, _ in pairs(self) do
        return false
    end
    return true
end

a = { }
print(table.empty(a))
a["hi"] = 2
print(table.empty(a))
a["hi"] = nil
print(table.empty(a))

Ausgabe:

true
false
true

11
next()ist effizienter (und prägnanter) als das Schleifen pairs().
Amber

7
In der Tat, Schleifen über pairs() ist im Wesentlichen nur die Verwendung von next()Technik, aber mit Aufwand mehr.
Dubiousjim

7
Das Schreiben in die Standardbibliothek tablewird ebenfalls nicht empfohlen.
Ti Strga

-1

Vermeiden Sie besser die Auswertung von __eq bei Überlastung.

if rawequal(next(myTable), nil) then
   -- myTable is empty
end

oder

if type(next(myTable)) == "nil" then
   -- myTable is empty
end

1
Ich bin ein Lua Noob, der versucht zu verstehen, warum diese Antwort abgelehnt wurde. Ich vermute, das liegt daran, dass in Lua "wenn zwei Objekte unterschiedliche Metamethoden haben, die Gleichheitsoperation zu false führt, ohne eine Metamethode aufzurufen". (Das Zitat befindet sich am Ende dieser Seite von Programming in Lua auf lua.org ). Beseitigt dies die Notwendigkeit, eine Überladung mit __eq für Null zu vermeiden?
SansWit

-1

versuche es mit der Schlange, arbeite für mich

serpent = require 'serpent'

function vtext(value)
  return serpent.block(value, {comment=false})
end

myTable = {}

if type(myTable) == 'table' and vtext(myTable) == '{}' then
   -- myTable is empty
end

-2

Wie wäre es damit ?

if endmyTable[1] == nil then
  -- myTable is empty
end

1
Dies funktioniert nicht auf einer Tabelle, die als Zeichenfolgen wie die von Index
SamHoque

-3

Ich weiß, dass dies alt ist, und ich könnte Sie irgendwie missverstehen, aber Sie möchten nur, dass die Tabelle leer ist, es sei denn, Sie überprüfen nur, ob dies der Fall ist und Sie möchten oder brauchen, dass sie nicht leer ist. Sie können es löschen, indem Sie es einfach neu erstellen, es sei denn, ich irre mich. Dies kann mit der folgenden Syntax erfolgen.

yourtablename = {} -- this seems to work for me when I need to clear a table.

4
Das ist nicht die Frage.
Yu Hao

-6

Versuchen Sie es mit #. Es gibt alle Instanzen zurück, die sich in einer Tabelle befinden. Wenn eine Tabelle keine Instanzen enthält, wird sie zurückgegeben0

if #myTable==0 then
print('There is no instance in this table')
end

1
Der Fragesteller sagt, dass dies #hier nicht ausreicht, und gibt Gründe dafür an; Können Sie erklären, warum dies diese Gründe umgeht?
ameed

Nun ... ich weiß es nicht. Ich bin neu in diesem Bereich. Der einzige Weg, den ich kenne, ist die Verwendung von #
arthurgps2 am
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.