Oft möchte man zusammengehörige Daten in einer Datenstruktur speichern, sodass auf einem einfachen Weg darauf zugreifen kann. Bevor wir uns in ausschweifenden Erklärungen verlieren, hier ein simples Beispiel:

-- Schlechtes Beispiel
local spieler_name    = "Max"
local spieler_energie = 100

Jetzt haben wir zwei Variablen mit jeweils einem Wert. Das funktioniert und ist an sich absolut in Ordnung. Es ergeben sich aber Nachteile, die wir ganz einfach ausmerzen können. Stelle dir vor wir wollen ein Spiel entwickeln. Wenn es nur einen Spieler gibt, und dieser nur diese beiden Eigenschaften hat, ok. Dann reicht das aus. Nun wollen wir der Spielwelt aber weitere Spieler, Gegner und andere Objekte hinzufügen. Dann müssten wir erst mal eine endlos lange Liste mit Variablennamen schreiben. Stellen wir fest, dass ein Gegner eine weitere Eigenschaft benötigt, müssten wir sie manuell hinzufügen und es ergibt sich eine lange Liste potentieller Fehler und unnötiger Arbeit.

Also wie können wir uns das einfacher machen? Mit einem Table. Im Gegensatz zu anderen Programmiersprachen gibt es in Lua nur eine Datenstruktur. Und die nennt sich Table. Sie ist sehr dynamisch und man kann sie für allerlei Dinge verwenden, wie zum Beispiel Arrays.

Den Begriff Arrays kennst du vielleicht schon aus anderen Programmiersprachen. Falls nicht, möchte ich es kurz erklären. Ein Array kann man sich vorstellen, wie ein Regal. Dieses Regal hat so viele Fächer wie du willst und jedes Fach hat eine eigene Nummer.

INFO: In anderen Programmiersprachen sind Arrays ein eigener Datentyp. Hier verwenden wir Table wie ein Array und sprechen daher von einem Array um deutlicher zu machen, dass wir nur eine von vielen Anwendungsmöglichkeiten der Tables besprechen. Ansonsten sollte man immer im Hinterkopf behalten, dass jede Datenstruktur in Lua ein Table ist.

Um in Lua ein solches Array zu erstellen, gehen wir genauso vor, wie bei normalen Variablen, nur das wir den Inhalt des Arrays mit geschweiften Klammern umschließen:

local array = {"spieler"}

Das wäre nun ein Array mit einem Wert oder Fach. Wir können aber so viele Werte hinzufügen, wie wir möchten:

local things = {"Apfel", "Auto", "Fahrrad", 2}

Die Zahl am Ende habe ich hinzugefügt um zu verdeutlichen, dass wir diesem Array alle möglichen Werte hinzufügen können. Strings wie Apfel oder Auto müssen weiterhin in Anführungszeichen stehen, während alle anderen Werte ohne Anführungszeichen hinzugefügt werden (ansonsten werden daraus automatisch Strings).

Jeder Wert erhält automatisch einen Index. Ein Index ist der Name über den wir auf einen bestimmten Wert im Array zugreifen können. Im Beispiel oben erhält jeder Wert automatisch einen Index in Form einer Zahl, die automatisch hochgezählt wird und immer bei 1 beginnt. Um darauf zuzugreifen verwenden wir nun den Namen der Variablen, gefolgt von eckigen Klammern. Innerhalb der eckigen Klammern steht der Index:

-- Einen Wert ausgeben
-- INFO: Der Index beginnt bei 1
print(things[1]) --> Apfel
print(things[2]) --> Auto
-- usw

Um Werte in einem Array zu ändern, müssen wir den Index kennen. Mit things[1] = "Banane" können wir den Wert ganz einfach bearbeiten. Möchten einen weiteren Wert hinzufügen, könnten wir zum Beispiel einfach den Index selbst festlegen:

things[5] = "Max"

Das birgt allerdings die Gefahr, dass man einen Wert überschreibt, den man gar nicht überschreiben wollte. Und man muss ständig im Auge haben, wie viele Werte das Array hält. Aber darum wollen wir uns nicht kümmern. Daher empfiehlt es sich eine der zahlreichen Funktionen zu verwenden, die Lua standardmäßig liefert. Eine davon ist table.insert().

Das hatten wir bisher noch nicht, daher eine kurze Erklärung: table ist eine Sammlung von Funktionen für Tables. Wie insert(). Neben insert() enthält table noch weitere hilfreiche Funktionen. Wichtig ist aber, dass wir sie immer über table. aufrufen müssen.

Die Funktion nimmt zwei Parameter entgegen. Der erste Parameter ist das Array (das in Wirklichkeit einfach ein Table ist), dem ein Wert hinzugefügt werden soll. Der zweite Parameter ist der Wert, der hinzugefügt werden soll. Die Funktion fügt es automatisch ans Ende des Arrays, ohne dabei Werte zu überschreiben:

table.insert(things, "Rupert")

Jetzt können wir Daten hinzufügen und ausgeben. Allerdings scheint das alles noch nicht wirklich praktisch zu sein. Daher schauen wir uns nun an, wie wir automatisch alle Daten ausgeben können, die sich in einem Array befinden. Und dafür benötigen wir eine Schleife:

-- Normale for-Schleife
for i = 1, 5 do
  print("Objekt: ", things[i])
end

Das wäre die einfachste Möglichkeit. Wir verwenden den Iterator (Zählvariable) um damit auf die Werte des Arrays zuzugreifen. Der große Nachteil ist, dass wir hier immer wissen müssen wie groß das Array ist.

Lua bietet daher noch ein paar weitere Möglichkeiten an. Zum Beispiel die maxn()-Funktion. Diese gibt uns den höchsten Index des Arrays zurück. Damit können wir also die For-Schleife genau so oft laufen lassen, wie wir es brauchen:

for i = 1, table.maxn(things) do
  print ("Objekt:", things[i])
end

Es gibt noch eine weitere Methode. Schauen wir uns direkt mal ein Beispiel ein:

--[[
    Ausgabe über for in mit ipairs
    Key - Schlüssel oder Index
    Value - Der Wert auf den man über den Key zugreifen kann

    things[1] --> Apfel
              ^      ^---^
              |         +---> Value      
              |
              +------------> Key
--]]

for key,value in ipairs(things) do
   print(key,value)
end

In dieser For-Schleife legen wir zuerst zwei Variablen fest. Key und Value. Wobei Key der Index des Arrays ist und Value eben der Wert dahinter. Dazu kommt das Schlüsselwort in und die Funktion ipairs(). Die Funktion ipairs() gibt uns ein Key-Value-Paar des Tables zurück. Dadurch erhalten wir automatisch also alles was wir brauchen. Und über die Variablen key und value haben wir auch unkomplizierten Zugriff auf die Werte im Array und müssen dafür auch nicht den Index eines bestimmten Wertes kennen.

Nun gibt es aber noch eine Sache, die ich bisher nicht erklärt habe. Und das ist die Tatsache, dass der Index nicht numerisch sein muss. Das Zählen des Arrays funktioniert natürlich super. Aber nicht, wenn man eigene Namen als Index verwendet. Warum man eigene Namen verwenden könnte? Um das zu beantworten schauen wir uns an, wie wir das erste Beispiel des Kapitels nun besser umsetzen können:

local spieler = {}
spieler["name"]   = "max"
spieler["leben"]  = 3

In der ersten Zeile erstellen wir ein leeres Table/Array und erstellen daraufhin eigene Einträge mit den Namen Name und Leben. Der Index hat nun also keinen Zahlenwert mehr. Dafür können wir aber sehr einfach auf die Werte des Spielers zugreifen. Auf diese Weise ist das Skript lesbarer und wir wissen immer auf welchen Wert wir zugreifen.

Das hat jedoch den einen oder anderen Nachteil. Zum Beispiel können wir das nicht einfach durchzählen. Aber mit der For-Schleife aus dem vorherhigen Beispiel, können wir auch dieses Array automatisiert durchlaufen:

for key,value in pairs(spieler) do
   print(key,value)
end

Einen wichtigen Unterschied gibt es hier aber. Statt ipairs() verwenden wir hier pairs(). Ohne das i am Anfang. Macht im Grunde genau das Gleiche, jedoch ignoriert ipairs() jeden Index, der nicht numerisch ist. Wir könnten hier also zwar ipairs verwenden, würden aber keine Ausgabe erhalten.

Kommen wir zum großen Finale des Kapitels. Jetzt hast du Tables und Arrays kennengelernt und weißt, was man damit anstellen kann. Nun wollen wir das alles mal praktisch nutzen. Denn was nutzt uns das alles, wenn wir die Probleme, die wir eingangs besprochen haben, immer noch nicht lösen können.

Der Trick an der ganzen Sache ist, dass wir Arrays in Arrays speichern können. Bzw. können wir Tables in einem Table speichern:

local user  = {} -- Leeres user-array
local users = {} -- leeres users-array

-- Neuen User erstellen
user["name"]    = "Max"
user["alter"]   = 20
user["energie"] = 100

table.insert(users, user)

Wir erstellen also zwei Tables. Eins für den einzelnen User. Ein Weiteres um die einzelnen User darin zu speichern. Und ausgeben, können wir den Spaß dann wie folgt:

for key, value in pairs(users) do
  print(key, value["name"], value["alter"], value["energie"])
end

Der Value ist in dem Fall immer das Array, dass wir darin abgelegt haben. Daher müssen wir nun den jeweiligen Wert über den Index abrufen.
Das sieht doch schon nach einer sinnvollen Anwendungsmöglichkeit aus. Um neue User hinzuzufügen muss man aber jedes Mal manuell einen erstellen. Da könnten wir uns noch etwas Schreibarbeit sparen, indem wir das ganze Prozedere in eine Funktion packen. Also eine gute Möglichkeit ein paar der bisher gelernten Dinge zu vertiefen.

Versuche diese kleine Aufgabe zu lösen. Die Lösung findest du direkt im Anschluss:
Erweitere das folgende Skript um eine Funktion namens addUser(). Diese Funktion soll dem Array/Table users einen neuen user hinzufügen. Dafür muss sie drei Parameter entgegennehmen: Name, Alter und Energie.

--[[
    Lösung zur Übung
--]]

local users = {} -- leeres users-table

function addUser(name, alter, energie)
  local user      = {}
  user["name"]    = name
  user["alter"]   = alter
  user["energie"] = energie

  table.insert(users, user)
end

addUser("Max", 20, 100)
addUser("Maria", 20, 100)
addUser("Eugene", 20, 100)

print("Index", "Name", "Alter", "Energie")
for key, value in pairs(users) do
  print(key, value["name"], value["alter"], value["energie"])
end

Es gibt noch so viel mehr zum Thema Tables zu besprechen. Aber dazu kommen wir später.

Tags: Grundlagen Tutorial

Letzte Bearbeitung:27.02.21 13:47 Uhr

 273

^ Nach oben

 Kommentare

Es wurden noch keine Kommentare geschrieben.