LUA Tables

From ESOUI Wiki

Jump to: navigation, search

Contents

Everything is a table

Ever coded in Ruby or Python? In those, everything defaults to object and is dynamically typecast via duck typing (if it walks like a duck and talks like a duck, the compiler will treat it as a duck).
In LUA, everything defaults to tables.

What does that mean for me?

The only data structure is a table. Functions? Stored in a table. Variables? Stored in a table.

local MyAddOn = {}
MyAddOn.defaults = {
 
}
MyAddOn.myString = "wasd"
 
function MyAddOn.MyFunction(arg1, arg2) return end
 
d(type(MyAddOn.MyFunction))    -- table
d(type(MyAddOn.defaults))      -- table
d(type(MyAddOn.myString))      -- string

UsingTables

Tables are Maps

When I say table, I actually mean map. If you define a table without explicit mapping, values will be mapped to the integers in order:

local tbl = {1, "Some Value", 10}
 
for key, value in pairs(tbl) do d(key .. " => " .. value) end
 
-- 1 => 1
-- 2 => "Some Value"
-- 3 => 10


Valid Keys/Values

You can have numerically indexed tables, or full maps/dictionaries. You can use numbers, strings, and nil as keys. </br> Tables are by default not ordered - if you want to sort your tables, or keep ordered/linked lists, you need to go with sequential numerical indices.

local tbl = {	[1] = "one", 	[2] = "two", 	[3] = "three" }
for key, value in pairs(tbl) do d(key .. " => " .. value) end
 
-- 1 => one
-- 2 => two
-- 3 => three

pairs vs ipairs

Pairs will iterate through all values in the table. However, there is no guarantee as to what order it will use.

local tbl = { ["one"] = 1, 	["two"] = 2, 	["three"] = 3 }
for key, value in pairs(tbl) do d(key .. " => " .. value) end
 
-- one => 1
-- three => 3
-- two => 2

BUT: ipairs are indexed pairs. It will start at index 1, and iterate up sequentially until the first nil value.

local tbl = { ["one"] = 1, 	["two"] = 2, 	["three"] = 3 , [4] = 4}
for key, value in ipairs(tbl) do d(key .. " => " .. value) end
 
-- Outputs nothing! There is no value for tbl[1]!
 
local tbl2 = { [1] = 1, 	[2] = 2, 	[3] = 3 , [5] = 5}
for key, value in ipairs(tbl2) do d(key .. " => " .. value) end
 
-- 1 => 1
-- 2 => 2
-- 3 => 3
-- Does not output 5, because there is no value for tbl2[4]!

Count your Entries

You can count numerically indexed tables with #:

local tbl = {	[1] = "one", 	[2] = "two", 	[3] = "three" }
d(#tbl) 	-- 3

BUT:

local tbl = {	[1] = "one", 	[2] = "two", 	[4] = "four" }
-- Since there is no value for tbl[3], it only outputs 2!
d(#tbl) 	-- 2

If you want to count the entries in a non-numerically indexed table, or a table that has a numeric index that's not continuous, use NonContiguousCount from their zo_tableutils:

var tbl = {	[1] = "one", 	[2] = "two", 	[4] = "four" }
d(NonContiguousCount (tbl))
 
-- 3

Should you wish to make your own, you can use pairs() with a counter.

Functions

Assume you want to run several functions every time something else happens, and you'll decide which based on what happens. What would be an elegant way to deal with that? (lengthy convoluted example)

MyAddOn = {
	MyFunction1 = function(arg) d("MyFunction1: called with " .. arg) end
	MyFunction2 = function(arg) d("MyFunction2: called with " .. arg) end
}
function MyAddOn.MyFunction3(arg) d("MyFunction3: called with " .. arg) end
function MyAddOn.MyFunction4(arg) d("MyFunction4: called with " .. arg) end
 
 
local function runCallbackFuncs(callbackList)
	for callback, args in pairs(callbackList) do callback(args) end
end
 
-- if event 1 happens: Call function 1 and 2
local function triggerOne()
	local callbackList = {
		[MyAddOn.MyFunction1] = {"triggerOne calling MyFunction1"}, 
		[MyAddOn.MyFunction2] = {"triggerOne calling MyFunction2"}, 
	}
	runCallbackFuncs(callbackList)
end
-- if event 2 happens: Call function 3 and 4
local function triggerTwo()
	local callbackList = {
		[MyAddOn.MyFunction3] = {"triggerTwo calling MyFunction3"}, 
		[MyAddOn.MyFunction4] = {"triggerTwo calling MyFunction4"}, 
	}
	runCallbackFuncs(callbackList)
end
 
--------------------
-- now we test it --
--------------------
MyAddOn.MyFunction1("this is a test")
-- this is a test
 
triggerOne()
-- MyFunction1: called with triggerOne calling MyFunction1
-- MyFunction2: called with triggerOne calling MyFunction2
 
triggerTwo()
-- MyFunction3: called with triggerTwo calling MyFunction3
-- MyFunction4: called with triggerTwo calling MyFunction4
Personal tools
Namespaces
Variants
Actions
Menu
Wiki
Toolbox