Suche…


Syntax

  • ipairs (numeric_table) - Lua-Tabelle mit Iterator für numerische Indizes
  • Paare (input_table) - generischer Lua-Tabelleniterator
  • key, value = next (input_table, input_key) - Lua-Tabellenwert-Wähler
  • table.insert (input_table, [position], value) - fügt den angegebenen Wert in die Eingabetabelle ein
  • remove_value = table.remove (input_table, [position]) - Legt den letzten Wert an oder entfernt den durch position angegebenen Wert

Bemerkungen

Tabellen sind die einzige in Lua verfügbare integrierte Datenstruktur. Dies ist entweder elegant oder verwirrend, je nachdem, wie Sie es betrachten.

Eine Lua-Tabelle ist eine Sammlung von Schlüssel-Wert-Paaren, bei denen die Schlüssel eindeutig sind und weder der Schlüssel noch der Wert gleich nil . Daher kann eine Lua-Tabelle einem Wörterbuch, einer Hashmap oder einem assoziativen Array aus anderen Sprachen ähneln. Viele strukturelle Muster können mit Tabellen erstellt werden: Stapel, Warteschlangen, Sets, Listen, Diagramme usw. Schließlich können Tabellen verwendet werden, um Klassen in Lua zu erstellen und ein Modulsystem zu erstellen.

Lua erzwingt keine besonderen Regeln für die Verwendung von Tabellen. Die in einer Tabelle enthaltenen Elemente können eine Mischung aus Lua-Typen sein. Eine Tabelle kann beispielsweise Strings, Funktionen, Booleans, Zahlen und sogar andere Tabellen als Werte oder Schlüssel enthalten.

Eine Lua-Tabelle mit aufeinanderfolgenden positiven Ganzzahl-Schlüsseln, die mit 1 beginnen, hat eine Sequenz. Die Schlüsselwertpaare mit positiven Ganzzahlschlüsseln sind die Elemente der Sequenz. Andere Sprachen nennen dies ein 1-basiertes Array. Bestimmte Standardoperationen und -funktionen funktionieren nur in der Reihenfolge einer Tabelle und einige haben ein nicht deterministisches Verhalten, wenn sie auf eine Tabelle ohne Reihenfolge angewendet werden.

Wenn Sie einen Wert in einer Tabelle auf nil wird er aus der Tabelle entfernt. Iteratoren sehen den zugehörigen Schlüssel nicht mehr. Beim Codieren einer Tabelle mit einer Sequenz ist es wichtig, zu vermeiden, dass die Sequenz unterbrochen wird. Entfernen Sie nur das letzte Element oder verwenden Sie eine Funktion wie die Standardtabelle table.remove , mit der Elemente nach unten table.remove , um die Lücke zu schließen.

Tabellen erstellen

Das Erstellen einer leeren Tabelle ist so einfach:

local empty_table = {}

Sie können auch eine Tabelle in Form eines einfachen Arrays erstellen:

local numeric_table = {
    "Eve", "Jim", "Peter"
}
-- numeric_table[1] is automatically "Eve", numeric_table[2] is "Jim", etc.

Beachten Sie, dass die Tabellenindizierung standardmäßig bei 1 beginnt.

Es ist auch möglich, eine Tabelle mit assoziativen Elementen zu erstellen:

local conf_table = {
    hostname = "localhost",
    port     = 22,
    flags    = "-Wall -Wextra"
    clients  = {                -- nested table
        "Eve", "Jim", "Peter"
    }
}

Die obige Verwendung ist Syntaxzucker für das, was darunter liegt. Die Schlüssel in dieser Instanz sind vom Typ string. Die obige Syntax wurde hinzugefügt, damit Tabellen als Datensätze angezeigt werden. Diese Syntax im Datensatzstil wird mit der Syntax für das Indexieren von Tabellen mit Zeichenfolgenschlüsseln parallel geschaltet, wie im Tutorial "Grundlegende Verwendung" beschrieben.

Wie in den Anmerkungen erläutert, funktioniert die Record-Style-Syntax nicht für jeden möglichen Schlüssel. Außerdem kann ein Schlüssel einen beliebigen Wert eines beliebigen Typs haben, und in den vorherigen Beispielen wurden nur Zeichenfolgen und fortlaufende Nummern behandelt. In anderen Fällen müssen Sie die explizite Syntax verwenden:

local unique_key = {}
local ops_table = {
    [unique_key] = "I'm unique!"
    ["^"]  = "power",
    [true] = true
}

Tabellen iterieren

Die Lua-Standardbibliothek bietet eine pairs Funktion, die die Schlüssel und Werte einer Tabelle durchläuft. Beim Iterieren mit pairs gibt es keine festgelegte Reihenfolge für den Durchlauf, selbst wenn die Schlüssel der Tabelle numerisch sind .

for key, value in pairs(input_table) do
    print(key, " -- ", value)
end

Für Tabellen mit numerischen Tasten bietet Lua eine ipairs Funktion an. Die ipairs Funktion wird immer von table[1] , table[2] usw. iterieren, bis der erste nil gefunden wird.

for index, value in ipairs(numeric_table) do
    print(index, ". ", value)
end

Seien Sie gewarnt, dass die Iteration mit ipairs() bei einigen Gelegenheiten nicht wie gewünscht funktioniert:

  • input_table hat "Löcher". (Weitere Informationen finden Sie im Abschnitt "Vermeiden von Lücken in als Arrays verwendeten Tabellen".) Beispiel:

    table_with_holes = {[1] = "value_1", [3] = "value_3"}
    
  • Schlüssel waren nicht alle numerisch. Zum Beispiel:

    mixed_table = {[1] = "value_1", ["not_numeric_index"] = "value_2"}
    

Natürlich funktioniert Folgendes auch für eine Tabelle, die eine richtige Reihenfolge darstellt:

for i = 1, #numeric_table do
    print(i, ". ", numeric_table[i])
end

Eine numerische Tabelle in umgekehrter Reihenfolge zu iterieren ist einfach:

for i = #numeric_table, 1, -1 do
    print(i, ". ", numeric_table[i])
end

Eine letzte Möglichkeit zum Durchlaufen von Tabellen ist die Verwendung des next Selektors in einer generischen for Schleife . Wie bei pairs gibt es keine festgelegte Reihenfolge für den Durchlauf. (Die pairs Methode verwendet next intern. So verwendete next ist im Wesentlichen eine weiteren manuelle Version von pairs . Siehe pairs in Lua - next Referenzhandbuch und next in Lua - Referenzhandbuch für weitere Details.)

for key, value in next, input_table do
    print(key, value)
end

Grundlegende Verwendung

Die grundlegende Verwendung von Tabellen umfasst den Zugriff auf und das Zuweisen von Tabellenelementen, das Hinzufügen von Tabelleninhalten und das Entfernen von Tabelleninhalten. Diese Beispiele setzen voraus, dass Sie wissen, wie Sie Tabellen erstellen.

Zugriff auf Elemente

Angesichts der folgenden Tabelle

local example_table = {"Nausea", "Heartburn", "Indigestion", "Upset Stomach",
                       "Diarrhea", cure = "Pepto Bismol"}

Man kann den sequentiellen Teil der Tabelle mit der Index-Syntax indizieren, wobei das Argument für die Index-Syntax der Schlüssel des gewünschten Schlüsselwertpaares ist. Wie im Erstellungs-Tutorial erläutert, besteht der größte Teil der Deklarationssyntax aus syntaktischem Zucker zum Deklarieren von Schlüssel-Wert-Paaren. Sequentiell enthaltene Elemente wie die ersten fünf Werte in example_table verwenden aufsteigende ganzzahlige Werte als Schlüssel. Die Datensatzsyntax verwendet den Namen des Felds als Zeichenfolge.

print(example_table[2])        --> Heartburn
print(example_table["cure"])   --> Pepto Bismol

Für String-Schlüssel gibt es Syntaxzucker, um die Datensatz-Stil-Syntax für String-Schlüssel bei der Tabellenerstellung zu parallelisieren. Die folgenden zwei Zeilen sind gleichwertig.

print(example_table.cure)      --> Pepto Bismol
print(example_table["cure"])   --> Pepto Bismol

Sie können auf Tabellen mit Schlüsseln zugreifen, die Sie zuvor nicht verwendet haben. Dies ist kein Fehler wie in anderen Sprachen. Dadurch wird der Standardwert nil .

Elemente zuordnen

Sie können vorhandene Tabellenelemente ändern, indem Sie sie mit der Indexsyntax einer Tabelle zuordnen. Darüber hinaus steht die Indexierungssyntax für Datensätze zur Einstellung von Werten zur Verfügung

example_table.cure = "Lots of water, the toilet, and time"
print(example_table.cure)    --> Lots of water, the toilet, and time

example_table[2] = "Constipation"
print(example_table[2])      --> Constipation

Sie können einer vorhandenen Tabelle auch neue Elemente durch Zuweisung hinzufügen.

example_table.copyright_holder = "Procter & Gamble"
example_table[100] = "Emergency source of water"

Besonderer Hinweis: Einige Zeichenfolgen werden mit der Datensatzsyntax nicht unterstützt. Weitere Informationen finden Sie in den Anmerkungen.

Elemente entfernen

Wie bereits erwähnt, ist der Standardwert für einen Schlüssel ohne zugewiesenen Wert gleich nil . Um ein Element aus einer Tabelle zu entfernen, müssen Sie lediglich den Wert eines Schlüssels auf den Standardwert zurücksetzen.

example_table[100] = "Face Mask"

Die Elemente sind jetzt nicht von einem nicht gesetzten Element zu unterscheiden.

Tischlänge

Tabellen sind einfach assoziative Arrays (siehe Anmerkungen), aber wenn fortlaufende Ganzzahlschlüssel verwendet werden, die von 1 aus beginnen, hat die Tabelle eine Sequenz .

Das Ermitteln der Länge des Sequenzteils einer Tabelle erfolgt mit # :

local example_table = {'a', 'l', 'p', 'h', 'a', 'b', 'e', 't'}
print(#example_table)    --> 8

Sie können die Längenoperation verwenden, um Elemente einfach an eine Sequenztabelle anzufügen.

example_table[#example_table+1] = 'a'
print(#example_table)    --> 9

Im obigen Beispiel ist der vorherige Wert von #example_table 8 , durch Hinzufügen von 1 wird der nächste gültige Ganzzahlschlüssel in der Sequenz 9 example_table[9] = 'a' , also ... example_table[9] = 'a' . Dies funktioniert bei jeder Tischlänge.

Besonderer Hinweis: Wenn Sie Ganzzahlschlüssel verwenden, die nicht zusammenhängend sind und von 1 aus beginnen, wird die Sequenz zu einer spärlichen Tabelle . Das Ergebnis der Längenoperation ist in diesem Fall undefiniert. Siehe den Abschnitt "Anmerkungen".

Verwenden von Tabellenbibliotheksfunktionen zum Hinzufügen / Entfernen von Elementen

Eine andere Möglichkeit, Elemente zu einer Tabelle hinzuzufügen, ist die Funktion table.insert() . Die Einfügefunktion funktioniert nur für Sequenztabellen. Es gibt zwei Möglichkeiten, die Funktion aufzurufen. Das erste Beispiel zeigt die erste Verwendung, wobei einer den Index zum Einfügen des Elements angibt (das zweite Argument). Dadurch werden alle Elemente aus dem angegebenen Index um eine Position nach oben #table . Das zweite Beispiel zeigt die andere Verwendung von table.insert() , wobei der Index nicht angegeben ist und der angegebene Wert an das Ende der Tabelle angehängt wird (Index #table + 1 ).

local t = {"a", "b", "d", "e"}
table.insert(t, 3, "c")        --> t = {"a", "b", "c", "d", "e"}

t = {"a", "b", "c", "d"}
table.insert(t, "e")           --> t = {"a", "b", "c", "d", "e"}

Zu dem Parallelisieren von table.insert() zum Entfernen von Elementen gehört table.remove() . Ähnlich hat es zwei aufrufende Semantik: eine zum Entfernen von Elementen an einer bestimmten Position und eine zum Entfernen am Ende der Sequenz. Beim Entfernen aus der Mitte einer Sequenz werden alle folgenden Elemente um einen Index nach unten verschoben.

local t = {"a", "b", "c", "d", "e"}
local r = table.remove(t, 3)       --> t = {"a", "b", "d", "e"}, r = "c"

t = {"a", "b", "c", "d", "e"}
r = table.remove(t)                --> t = {"a", "b", "c", "d"}, r = "e"

Diese beiden Funktionen verändern die angegebene Tabelle. Möglicherweise können Sie auch die zweite Methode des Aufrufs von table.insert() und table.remove() , die Tabellen-Semantik bereitstellt. Wenn Sie dies nutzen, können Sie Code wie im folgenden Beispiel schreiben.

function shuffle(t)
    for i = 0, #t-1 do
        table.insert(t, table.remove(t, math.random(#t-i)))
    end
end

Es implementiert die Fisher-Yates-Shuffle möglicherweise ineffizient. Es verwendet table.insert() , um das zufällig extrahierte Element an das Ende derselben Tabelle anzuhängen, und table.remove() um zufällig ein Element aus dem verbleibenden, nicht gemischten Teil der Tabelle zu extrahieren.

Vermeidung von Lücken in Tabellen, die als Arrays verwendet werden

Unsere Bedingungen definieren

Unter Array verstehen wir hier eine Lua-Tabelle, die als Sequenz verwendet wird. Zum Beispiel:

-- Create a table to store the types of pets we like.
local pets = {"dogs", "cats", "birds"}

Wir verwenden diese Tabelle als Sequenz: eine Gruppe von Elementen, die durch Ganzzahlen eingegeben werden. Viele Sprachen nennen das ein Array und wir auch. Aber streng genommen gibt es in Lua kein Array. Es gibt nur Tabellen, von denen einige Array-artig sind, einige haschartig (oder wörterbuchartig, wenn Sie es vorziehen) und einige gemischt sind.

Ein wichtiger Punkt bei unserem pets Array ist, dass es keine Lücken gibt. Das erste Element, pets[1] , ist die Zeichenfolge "Hunde", das zweite Element, pets[2] , ist die Zeichenfolge "Katzen", und das letzte Element, pets[3] , ist "Vögel". Die Standardbibliothek von Lua und die meisten für Lua geschriebenen Module setzen 1 als ersten Index für Sequenzen voraus. Ein lückenloses Array enthält daher Elemente aus 1..n ohne dass Zahlen in der Reihenfolge fehlen. (Im Grenzfall ist n = 1 und das Array enthält nur ein Element.)

Lua bietet die integrierte Funktion ipairs , um solche Tabellen zu ipairs .

-- Iterate over our pet types.
for idx, pet in ipairs(pets) do
  print("Item at position " .. idx .. " is " .. pet .. ".")
end

Dies würde "Artikel an Position 1 sind Hunde" drucken, "Artikel an Position 2 sind Katzen.", "Artikel an Position 3 sind Vögel."

Was passiert aber, wenn wir Folgendes tun?

local pets = {"dogs", "cats", "birds"}
pets[12] = "goldfish"
for idx, pet in ipairs(pets) do
  print("Item at position " .. idx .. " is " .. pet .. ".")
end

Ein Array wie dieses zweite Beispiel ist ein Array mit geringer Dichte. Es gibt Lücken in der Reihenfolge. Dieses Array sieht folgendermaßen aus:

{"dogs", "cats", "birds", nil, nil, nil, nil, nil, nil, nil, nil, "goldfish"}
-- 1        2       3      4    5    6    7    8    9    10   11       12     

Die Nullwerte belegen keinen zusätzlichen Speicher. intern speichert lua nur die Werte [1] = "dogs" , [2] = "cats" , [3] = "birtds" und [12] = "goldfish"

Um die unmittelbare Frage zu beantworten, ipairs nach Vögeln stehen; "Goldfisch" bei pets[12] wird niemals erreicht, wenn wir nicht unseren Code anpassen. Dies liegt daran, dass ipairs von 1..n-1 wobei n die Position der ersten gefundenen nil ist. Lua definiert table[length-of-table + 1] als nil . In einer richtigen Reihenfolge stoppt die Iteration dann, wenn Lua versucht, das vierte Element in einem Array mit drei Elementen abzurufen.

Wann?

Die zwei häufigsten Stellen, an denen Probleme mit spärlichen Arrays auftreten können, sind (i) beim Versuch, die Länge des Arrays zu bestimmen, und (ii) beim Versuch, das Array zu durchlaufen. Im Speziellen:

  • Wenn Sie den Operator # length verwenden, da der Längenoperator mit dem ersten gefundenen nil nicht mehr zählt.
  • Bei der Verwendung von ipairs() Funktion , da , wie oben erwähnt es bei der ersten stoppt Iterieren nil gefunden.
  • Bei Verwendung der table.unpack() Funktion , da diese Methode stoppt beim ersten Auspacken nil gefunden.
  • Bei Verwendung anderer Funktionen, die (direkt oder indirekt) auf eine der oben genannten Funktionen zugreifen.

Um dieses Problem zu vermeiden, ist es wichtig, Ihren Code zu schreiben, damit Sie, wenn Sie erwarten, dass eine Tabelle ein Array ist, keine Lücken einführen. Lücken können auf verschiedene Weise eingeführt werden:

  • Wenn Sie etwas zu einem Array an der falschen Position hinzufügen.
  • Wenn Sie einen nil in ein Array einfügen.
  • Wenn Sie Werte aus einem Array entfernen.

Sie denken vielleicht: "Aber ich würde nie eines dieser Dinge tun." Nun, nicht absichtlich, aber hier ist ein konkretes Beispiel, wie etwas schief gehen könnte. Stellen Sie sich vor, Sie möchten eine Filtermethode für Lua wie Ruby's select und Perl's grep schreiben. Die Methode akzeptiert eine Testfunktion und ein Array. Es durchläuft das Array und ruft die Testmethode für jedes Element der Reihe nach auf. Wenn das Element erfolgreich ist, wird dieses Element einem Ergebnisfeld hinzugefügt, das am Ende der Methode zurückgegeben wird. Folgendes ist eine fehlerhafte Implementierung:

local filter = function (fun, t)
  local res = {}
  for idx, item in ipairs(t) do
    if fun(item) then
      res[idx] = item
    end
  end

  return res
end

Das Problem ist, dass, wenn die Funktion false zurückgibt, eine Zahl in der Sequenz übersprungen wird. Stellen Sie sich vor, Sie rufen filter(isodd, {1,2,3,4,5,6,7,8,9,10}) : Es gibt immer Lücken in der zurückgegebenen Tabelle, wenn eine gerade Zahl im Array an filter .

Hier ist eine feste Implementierung:

local filter = function (fun, t)
  local res = {}
  for _, item in ipairs(t) do
    if fun(item) then
      res[#res + 1] = item
    end
  end

  return res
end

Tipps

  1. Verwenden Sie Standardfunktionen: table.insert(<table>, <value>) hängt immer am Ende des Arrays an. table[#table + 1] = value ist hierfür eine kurze Hand. table.remove(<table>, <index>) verschiebt alle folgenden Werte zurück, um die Lücke zu füllen (was auch dazu führen kann, dass sie langsam wird).
  2. Überprüfen Sie für nil - Werte vor dem Einfügen, die Vermeidung Dinge wie table.pack(function_call()) , die schleichen könnte nil - Werte in unserer Tabelle.
  3. Prüfen Sie nach dem Einfügen auf nil und füllen Sie ggf. die Lücke, indem Sie alle aufeinander folgenden Werte verschieben.
  4. Verwenden Sie nach Möglichkeit Platzhalterwerte. Ändern Sie beispielsweise nil für 0 oder einen anderen Platzhalterwert.
  5. Wenn Lücken nicht vermeidbar sind, sollte dies gut dokumentiert (kommentiert) werden.
  6. Schreiben Sie eine __len() -Methode und verwenden Sie den Operator # .

Beispiel für 6 .:

tab = {"john", "sansa", "daenerys", [10] = "the imp"}
print(#tab) --> prints 3
setmetatable(tab, {__len = function() return 10 end})
-- __len needs to be a function, otherwise it could just be 10
print(#tab) --> prints 10
for i=1, #tab do print(i, tab[i]) end
--> prints:
-- 1 john
-- 2 sansa
-- 3 daenerys
-- 4 nil
-- ...
-- 10 the imp

for key, value in ipairs(tab) do print(key, value) end
--> this only prints '1 john \n 2 sansa \n 3 daenerys'

Eine andere Alternative besteht darin, die pairs() Funktion zu verwenden und die Nicht-Ganzzahl-Indizes herauszufiltern:

for key in pairs(tab) do
    if type(key) == "number" then
        print(key, tab[key]
    end
end
-- note: this does not remove float indices
-- does not iterate in order


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow