Zoeken…


Syntaxis

  • ipairs (numerieke_tabel) - Lua-tabel met iterator met numerieke indices
  • paren (input_table) - generieke Lua-tabeliterator
  • key, value = next (input_table, input_key) - Lua tabel waardekiezer
  • table.insert (input_table, [position], value) - voer de opgegeven waarde in de invoertabel in
  • remove_value = table.remove (input_table, [position]) - knal als laatste of verwijder de waarde gespecificeerd door position

Opmerkingen

Tabellen zijn de enige ingebouwde datastructuur die beschikbaar is in Lua. Dit is elegante eenvoud of verwarrend, afhankelijk van hoe je het bekijkt.

Een Lua-tabel is een verzameling sleutel / waarde-paren waarbij de sleutels uniek zijn en noch de sleutel, noch de waarde nil . Als zodanig kan een Lua-tabel lijken op een woordenboek, hashmap of associatieve array uit andere talen. Veel structurele patronen kunnen worden gebouwd met tabellen: stapels, wachtrijen, sets, lijsten, grafieken, enz. Ten slotte kunnen tabellen worden gebruikt om klassen in Lua te bouwen en een modulesysteem te maken.

Lua hanteert geen specifieke regels voor het gebruik van tabellen. De items in een tabel kunnen een combinatie van Lua-typen zijn. Eén tabel kan dus bijvoorbeeld tekenreeksen, functies, booleans, getallen en zelfs andere tabellen als waarden of toetsen bevatten.

Van een Lua-tabel met opeenvolgende positieve gehele getallen die met 1 beginnen, wordt gezegd dat deze een reeks heeft. De sleutel / waarde-paren met positieve geheeltallige sleutels zijn de elementen van de reeks. Andere talen noemen dit een op 1 gebaseerde array. Bepaalde standaardbewerkingen en functies werken alleen op de volgorde van een tabel en sommige hebben niet-deterministisch gedrag wanneer ze worden toegepast op een tabel zonder een reeks.

Als u een waarde in een tabel op nil wordt deze uit de tabel verwijderd. Iterators zouden de bijbehorende sleutel niet langer zien. Wanneer u codeert voor een tabel met een reeks, is het belangrijk om de reeks niet te breken; Verwijder alleen het laatste element of gebruik een functie, zoals de standaard table.remove , dat verschuivingen elementen naar het dichten.

Tabellen maken

Een lege tabel maken is zo eenvoudig als dit:

local empty_table = {}

U kunt ook een tabel maken in de vorm van een eenvoudige array:

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

Houd er rekening mee dat het indexeren van tabellen standaard begint bij 1.

Het is ook mogelijk om een tabel met associatieve elementen te maken:

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

Het bovenstaande gebruik is syntaxisuiker voor wat hieronder staat. De sleutels in dit geval zijn van het type string. De bovenstaande syntaxis is toegevoegd om tabellen als records weer te geven. Deze syntaxis in recordstijl loopt parallel met de syntaxis voor indexeringstabellen met string-toetsen, zoals te zien in de tutorial 'basisgebruik'.

Zoals uitgelegd in het gedeelte met opmerkingen, werkt de syntaxis van de recordstijl niet voor elke mogelijke sleutel. Bovendien kan een sleutel elke waarde van elk type hebben, en de vorige voorbeelden hadden alleen betrekking op tekenreeksen en opeenvolgende getallen. In andere gevallen moet u de expliciete syntaxis gebruiken:

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

Tabellen herhalen

De standaardbibliotheek van Lua biedt een pairs die de toetsen en waarden van een tabel doorloopt. Bij het itereren met pairs er geen gespecificeerde volgorde voor doorkruisen, zelfs als de toetsen van de tabel numeriek zijn .

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

Voor tabellen die numerieke toetsen gebruiken , biedt Lua een ipairs functie. De functie ipairs zal altijd doorgaan van table[1] , table[2] , enz. Totdat de eerste nil is gevonden.

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

Wees gewaarschuwd dat iteratie met behulp van ipairs() in enkele gevallen niet werkt zoals u misschien wilt:

  • input_table heeft "gaten" erin. (Zie het gedeelte over "Vermijden van gaten in tabellen die als arrays worden gebruikt" voor meer informatie.) Bijvoorbeeld:

    table_with_holes = {[1] = "value_1", [3] = "value_3"}
    
  • toetsen waren niet allemaal numeriek. Bijvoorbeeld:

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

Natuurlijk werkt het volgende ook voor een tabel die de juiste volgorde heeft:

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

Een numerieke tabel in omgekeerde volgorde herhalen is eenvoudig:

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

Een laatste manier om door tabellen te bladeren, is door de next selector in een generieke for lus te gebruiken . Net als pairs er geen opgegeven volgorde voor doorkruisen. (De pairs methode gebruikt next intern. Dus het gebruik van next is in wezen een meer handmatige versie van pairs . Zie pairs in Lua's referentiehandleiding en de next in Lua's referentiehandleiding voor meer details.)

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

Basisgebruik

Het basisgebruik van tabellen omvat het openen en toewijzen van tabelelementen, het toevoegen van tabelinhoud en het verwijderen van tabelinhoud. In deze voorbeelden wordt ervan uitgegaan dat u weet hoe u tabellen kunt maken.

Toegang tot elementen

Gezien de volgende tabel,

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

Men kan het sequentiële deel van de tabel indexeren met behulp van de indexsyntaxis, waarbij het argument voor de indexsyntaxis de sleutel is van het gewenste sleutel / waarde-paar. Zoals uitgelegd in de creatie-tutorial, is de meeste declaratiesyntaxis syntactische suiker voor het declareren van sleutel / waarde-paren. Achtereenvolgens opgenomen elementen, zoals de eerste vijf waarden in example_table , gebruiken toenemende gehele waarden als sleutels; de recordsyntaxis gebruikt de naam van het veld als een tekenreeks.

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

Voor tekenreekstoetsen is er syntaxisuiker om de syntaxis van de recordstijl voor tekenreekstoetsen parallel te maken bij het maken van tabellen. De volgende twee regels zijn equivalent.

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

U kunt toegang krijgen tot tabellen met sleutels die u nog niet eerder hebt gebruikt, dat is geen fout zoals in andere talen. Als u dit doet, wordt de standaardwaarde nil geretourneerd.

Elementen toewijzen

U kunt bestaande tabelelementen wijzigen door aan een tabel toe te wijzen met behulp van de indexsyntaxis. Bovendien is de index-syntaxis in recordstijl beschikbaar voor het instellen van waarden

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

U kunt ook nieuwe elementen aan een bestaande tabel toevoegen met behulp van een opdracht.

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

Speciale opmerking: sommige tekenreeksen worden niet ondersteund met de record-syntaxis. Zie het opmerkingen gedeelte voor details.

Elementen verwijderen

Zoals eerder vermeld, is de standaardwaarde voor een sleutel zonder toegewezen waarde nil . Een element uit een tabel verwijderen is net zo eenvoudig als het terugzetten van de waarde van een sleutel naar de standaardwaarde.

example_table[100] = "Face Mask"

De elementen zijn nu niet te onderscheiden van een niet-ingesteld element.

Tafel lengte

Tabellen zijn eenvoudig associatieve arrays (zie opmerkingen), maar wanneer aaneengesloten gehele getallen worden gebruikt, beginnend vanaf 1, wordt gezegd dat de tabel een reeks heeft .

Het vinden van de lengte van het sequentiedeel van een tabel wordt gedaan met # :

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

U kunt de lengtebewerking gebruiken om eenvoudig items aan een sequentietabel toe te voegen.

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

In het bovenstaande voorbeeld is de vorige waarde van #example_table 8 , als u 1 toevoegt, krijgt u de volgende geldige gehele sleutel in de reeks, 9 , dus ... example_table[9] = 'a' . Dit werkt voor elke lengte van de tafel.

Speciale opmerking: het gebruik van geheeltallige toetsen die niet aaneengesloten zijn en begint bij 1, breekt de reeks waardoor de tabel een schaarse tabel wordt . Het resultaat van de lengtebewerking is in dat geval niet gedefinieerd. Zie het opmerkingen gedeelte.

Tabelbibliotheekfuncties gebruiken om elementen toe te voegen / te verwijderen

Een andere manier om elementen aan een tabel toe te voegen, is de functie table.insert() . De invoegfunctie werkt alleen op sequentietabellen. Er zijn twee manieren om de functie aan te roepen. Het eerste voorbeeld toont het eerste gebruik, waarbij men de index specificeert om het element in te voegen (het tweede argument). Dit duwt alle elementen uit de gegeven index naar #table één positie omhoog. Het tweede voorbeeld toont het andere gebruik van table.insert() , waarbij de index niet is opgegeven en de opgegeven waarde aan het einde van de tabel is toegevoegd (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"}

Om table.insert() voor het verwijderen van elementen parallel te table.insert() is table.remove() . Op dezelfde manier heeft het twee roepende semantiek: een voor het verwijderen van elementen op een gegeven positie en een andere voor het verwijderen van het einde van de reeks. Bij het verwijderen uit het midden van een reeks, worden alle volgende elementen één index omlaag verplaatst.

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"

Deze twee functies muteren de gegeven tabel. Zoals u wellicht kunt zien, biedt de tweede methode voor het aanroepen van table.insert() en table.remove() stack-semantiek voor tabellen. Gebruikmakend van dat, kunt u code schrijven zoals in het onderstaande voorbeeld.

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

Het implementeert de Fisher-Yates Shuffle, misschien inefficiënt. Het gebruikt de table.insert() om het willekeurig geëxtraheerde element aan het einde van dezelfde tabel toe te voegen en de table.remove() om een element willekeurig uit het resterende niet-geschudde deel van de tabel te extraheren.

Vermijden van gaten in tabellen die als arrays worden gebruikt

Onze voorwaarden definiëren

Met array bedoelen we een Lua-tabel die als een reeks wordt gebruikt. Bijvoorbeeld:

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

We gebruiken deze tabel als een reeks: een groep items die worden getoetst door gehele getallen. Veel talen noemen dit een array, en wij ook. Maar strikt genomen bestaat er in Lua niet zoiets als een array. Er zijn alleen tabellen, waarvan sommige array-achtig zijn, sommige hash-achtig (of woordenboekachtig, als je dat liever hebt), en sommige zijn gemengd.

Een belangrijk punt van onze reeks pets is dat er geen gaten zijn. Het eerste item, pets[1] , is de string "honden", het tweede item, pets[2] , is de string "katten", en het laatste item, pets[3] , is "vogels". Lua's standaardbibliotheek en de meeste modules geschreven voor Lua gaan uit van 1 als de eerste index voor reeksen. Een gapless array bevat daarom items van 1..n zonder nummers in de reeks te missen. (In het beperkende geval is n = 1 en bevat de array slechts één item.)

Lua biedt de ingebouwde functie ipairs om dergelijke tabellen te ipairs .

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

Dit zou afdrukken "Item op positie 1 is honden.", "Item op positie 2 is katten.", "Item op positie 3 is vogels."

Maar wat gebeurt er als we het volgende doen?

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

Een array zoals dit tweede voorbeeld is een schaarse array. Er zitten gaten in de reeks. Deze array ziet er zo uit:

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

De nulwaarden nemen geen extra geheugen in beslag; intern bewaart lua alleen de waarden [1] = "dogs" , [2] = "cats" , [3] = "birtds" en [12] = "goldfish"

Om de directe vraag te beantwoorden, zullen ipairs stoppen na vogels; "goudvissen" bij pets[12] worden nooit bereikt tenzij we onze code aanpassen. Dit komt omdat ipairs itereert van 1..n-1 waarbij n de positie is van de eerste gevonden nil . Lua definieert table[length-of-table + 1] als nil . Dus in een juiste volgorde stopt iteratie wanneer Lua bijvoorbeeld het vierde item in een array met drie items probeert te krijgen.

Wanneer?

De twee meest voorkomende plaatsen voor problemen met schaarse arrays zijn (i) wanneer u probeert de lengte van de array te bepalen en (ii) wanneer u probeert over de array te itereren. Met name:

  • Wanneer u de operator # length gebruikt, omdat de operator length stopt met tellen bij de eerste gevonden nil .
  • Wanneer de functie ipairs() gebruikt, stopt het, zoals hierboven vermeld, bij de eerste gevonden nil .
  • Bij gebruik van de functie table.unpack() omdat deze methode stopt met uitpakken bij de eerste gevonden nil .
  • Wanneer u andere functies gebruikt die (direct of indirect) toegang hebben tot een van de bovenstaande functies.

Om dit probleem te voorkomen, is het belangrijk om uw code te schrijven, zodat u geen gaten invoert als u verwacht dat een tabel een array is. Hiaten kunnen op verschillende manieren worden aangebracht:

  • Als u iets op een verkeerde positie aan een array toevoegt.
  • Als u een nil in een array invoegt.
  • Als u waarden uit een array verwijdert.

Je zou kunnen denken: "Maar ik zou nooit iets van die dingen doen." Nou, niet opzettelijk, maar hier is een concreet voorbeeld van hoe dingen mis kunnen gaan. Stel je voor dat je een filtermethode voor Lua wilt schrijven, zoals Ruby's select en Perl's grep . De methode accepteert een testfunctie en een array. Het itereert over de array en roept om de beurt de testmethode op elk item aan. Als het item slaagt, wordt dat item toegevoegd aan een resultatenmatrix die aan het einde van de methode wordt geretourneerd. Het volgende is een buggy-implementatie:

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

Het probleem is dat wanneer de functie false retourneert, we een getal in de reeks overslaan. Stel je voor dat je een filter(isodd, {1,2,3,4,5,6,7,8,9,10}) : er zijn gaten in de geretourneerde tabel elke keer dat er een even getal in de array wordt doorgegeven om te filter .

Hier is een vaste implementatie:

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

Tips

  1. Gebruik standaardfuncties: table.insert(<table>, <value>) altijd toegevoegd aan het einde van de array. table[#table + 1] = value is hiervoor een korte hand. table.remove(<table>, <index>) verplaatst alle volgende waarden terug om het gat te vullen (wat het ook traag kan maken).
  2. Controleer op nil waarden voor het plaatsen, het vermijden van dingen als table.pack(function_call()) , wat kan sluipen nil waarden in onze tafel.
  3. Controleer op nil waarden na het invoegen en eventueel vullen van het gat door het verschuiven van alle opeenvolgende waarden.
  4. Gebruik indien mogelijk waarden voor tijdelijke aanduiding. Wijzig bijvoorbeeld nil voor 0 of een andere tijdelijke aanduiding-waarde.
  5. Als hiaten onvermijdelijk zijn, moet dit goed worden gedocumenteerd (becommentarieerd).
  6. Schrijf een __len() metamethod en gebruik de operator # .

Voorbeeld voor 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'

Een ander alternatief is om de pairs() -functie te gebruiken en de niet-gehele indices uit te filteren:

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow