how to populate nested tables in Lua? - lua

This must be embarrassingly easy, but I can't find the solution: I have a text file with data in this form:
| 1 | 1 | A | X |
| | 2 | A | Z |
| | | B | Y |
I would like to process this data with Lua, so I need to have it in a structured (nested) table like this (I hope the indentation comes out right):
t = {
['1'] =
{
['1'] =
{
{
{ ['A'] = 'X' },
},
},
['2'] =
{
{
{ ['A'] = 'Z' },
{ ['B'] = 'Y' },
},
},
},
}
But I can't figure out how to go from A to B. The structure is already kind of there, but how can I read it into Lua?

This will definitely do the task for you.
tTable = {}
OldIDX, OldIDX2, bSwitched, bSwitched2 = 0, 0, false, false
for str in io.lines("txt.txt") do
local _, _, iDx, iDex, sIdx, sVal = str:find( "^%| ([%d|%s]?) %| ([%d|%s]?) %| (%S?) %| (%S?) %|$" )
if not tonumber(iDx) then iDx, bSwitched = OldIDX, true end
if not tonumber(iDex) then iDex, bSwitched2 = OldIDX2, true end
OldIDX, OldIDX2 = iDx, iDex
if not bSwitched then
tTable[iDx] = {}
end
if not bSwitched2 then
tTable[iDx][iDex] = {}
end
bSwitched, bSwitched2 = false, false
tTable[iDx][iDex][sIdx] = sVal
end
NOTE
The only thing you can change in the code is the name of the file. :)
EDIT
Seems like I was wrong, you did need some changes. Made them too.

Assuming you can read in a line and get to the individual items between the |'s, the algorithm would be something like this (pseudo code, I'll use col(n) to indicate the character in the n'th column for the current line):
1. store current indices for columns 1 and 2 (local vars)
2. read line (if no more lines, go to 7.)
3. if col(1) not empty - set the currentCol1 index to col(1)
a. if t[currentCol1] == nil, t[currentCol1] = {}
4. if col(2) not empty - set the currentCol2 index to col(2)
a. if t[currentCol1][currentCol2] == nil, t[currentCol1][currentCol2] = {}
5. set t[currentCol1][currentCol2][col(3)] = col(4)
6. go to step 2.
7. return t
I hope this is mostly self explanatory. Except for step 2 you shouldn't have problems going from pseudo-code to lua (and we don't know how you're getting to that data to help you with step 2). If you're not sure about the able operations, I'd suggest going over "Tables as arrays" and "Tables as dictionaries" from this lua-users tutorial.
As a side note - your example seems to be double-nesting the A=X,A=Z,B=Y inside two tables. I suspect that instead of:
['2'] =
{
{
{ ['A'] = 'Z' },
{ ['B'] = 'Y' },
},
},
you meant:
['2'] =
{
{ ['A'] = 'Z' },
{ ['B'] = 'Y' },
},
so that's what the pseudo code should get you.

Related

Counting elements in nested table by name starting with

I have the table listed below
raids = {
{
T1I0 = {
{'Mightstone of Sargaras', 'Mightstone of Sargaras\n\nMightstone of Sargaras is obtained by farming. GL'}
},
T1I1 = {
{'Blessings Jewel of Elune', 'test'}
},
T1I2 = {
{'Lifegiving Gem of Amanthel', 'test'}
},
T2I0 = {
{'Practicing monster pot', 'test'}
},
T2I1 = {
{'Nuwa stone', 'test'}
}
}
}
I've managed to count the amount of elements T1I0 -> T2I1 = 5 by using the function below, combined with tablelength(raids[1])
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
But I'm having some problem with counting only elements starting with T1, sound return 3.
Anyone got an ide how I can modify the last part?
Try this code:
for k in pairs(T) do if k:sub(1,2)=="T1" then count = count + 1 end end
However, consider re-structuring the table in two layers, the first one having keys T1 and T2. After this, the count you want is simply #raids.T1.

Dynamically building subtables in a table

I'm trying to figure out how to dynamically build a series of sub-tables inside a lua table. For example
function BuildsubTable()
local oTable = {}
local name = {"P1","P2"}
for i = 1, 2 do
oTable[i] = {name = name[i], "x" = i + 2, "y" = i + 1}
end
return oTable
end
expected output:
oTable = {
{name = "P1", "x"=3, "y"=2},
{name = "P2", "x"=4, "y"=3}
}
Which obviously doesn't work, but you get the idea of what I'm trying to do. This is a rather simple task but in LUA 5.3 this is proving to be difficult. I cannot find a good example of building a table in this manner. Any solutions or other ideas would be appreciated. In Python I would use a class or a simple dictionary.
Your problem is that you quote the string indices. The generic syntax for declaring a table key inside the table constructor is [<key>] = <value>, for example, [20] = 20 or ["x"] = i + 2.
A shorthand for ["<key>"] = <value>, that is, for string indices that are valid variable names, you can write <key> = <value>, for example x = i + 2.
In your code you use a mix of both and write { ..., "x" = i + 2, ... }. A quick google search shows me that in Python, which you mention, you quote string keys in dictionaries, so you probably mixed that up with Lua?
EDIT: I noticed this a bit late, but you can also use ipairs to iterate the first table and table.insert to insert values:
function BuildsubTable()
local oTable = {}
local name = {"P1","P2"}
for i,name in ipairs(name) do
table.insert(oTable, {name = name, "x" = i + 2, "y" = i + 1})
end
return oTable
end
Use
oTable[i] = {name = name[i], x = i + 2, y = i + 1}
DarkWiiPlayers & lhf's answers are the proper way.
But here is how you can fix your current code if you intend to use a string as a key
function BuildsubTable()
local oTable = {}
local name = {"P1","P2"}
for i = 1, 2 do
oTable[i] = {name = name[i], ["x"] = i + 2, ["y"] = i + 1}
end
return oTable
end
Output
{
[1] = { ['name'] = 'P1', ['x'] = 3, ['y'] = 2},
[2] = { ['name'] = 'P2', ['x'] = 4, ['y'] = 3}
}

Sort table with gaps

I got a table which is not meant to be sorted in a way I need it to be sorted at a specific point.
Thus, I cannot sort the table while creation but have to sort it when needed.
Problem is, there are plenty gabs in the indeces and the Values I want to sort here are nested.
Simplified model:
table = {
[1] = { a = 1 , b = 31231, c = { c1 = "foo" , true } },
[8] = { a = 2 , b = 5231 , c = { c1 = "bar" , true } },
[92] = { a = 8 , b = 2 , c = { c1 ="asdgköbana" , false } },
}
Now I want to sort this table by length of c[1].
How can I do that in the fastest way? Length of table in first dimension will stay under 100 entries.
Indices don't need to be kept. So by a table with 3 entries, it's okay when last index is [3] after the portage. Basicly in this case, I only use the index to identifies neighbors, they have no prior use.
Using table as a variable kills the table library, which you need to get the sort function.
Try the code below. Note that it makes a new table to hold the sorted list but reuses the internal tables.
local t = {
[1] = { a = 1 , b = 31231, c = { c1 = "foo" , true } },
[8] = { a = 2 , b = 5231 , c = { c1 = "bar" , true } },
[92] = { a = 8 , b = 2 , c = { c1 ="asdgköbana" , false } },
}
local s = {}
for k,v in pairs(t) do
s[#s+1]=v
end
table.sort(s,function (a,b)
return #a.c.c1 < #b.c.c1
end)
for k,v in ipairs(s) do
print(k,v.a,v.c.c1)
end

Lua return index of a nested table

This is my first attempt to use Lua tables and I'm getting on with it quite well. I'm struggling with one thing though, heres (a small sample of) my table as it currently stands:
objects = {
["1/1/1"] = { tl = 1, startVal = 1, stopVal = 0 },
["1/1/2"] = { tl = 11, startVal = 1, stopVal = 0 },
["1/1/3"] = { tl = 22, startVal = 1, stopVal = 0 },
["1/1/4"] = { tl = 33, startVal = 1, stopVal = 0 },
}
The typical operation of this is that I use the "1/1/1" values as a lookup to the inner tables and then use those values in various functions. This all works well. Now, I need to go the other way, say I have tl = 22 coming in, I want to return the top value ("1/1/3" in this case).
I think I need to do something with the inpairs I keep seeing on the web but I'm struggling to implement. Any help would be massively appreciated.
You can't use ipairs because your table is an associated array not a sequence, so you have to use pairs. Also, there is no search function builtin to Lua, so you have to loop over all items yourself, looking for the right field value:
function findTL(tbl)
for key, data in pairs(tbl) do
if data.tl == tlSearch then
return key
end
end
end
local key = findTL(objects, 22)
If you want something a tad more object-oriented you could do this:
objects.findTL = findTL -- ok because first arg is the table to search
local key = objects:findTL(22)
isn't it better to take the value directly?
objects.1/1/1.tl
I don't know if it will work also with slashes, but if not, you may replace it by 'x' for example. Then it will be:
objects.1x1x1.tl

how to access data in such table?

I'm writing a program with lua. I have data that organized in the following way:
t= {
i1 = {
p1 = { value = "i1p1" },
p2 = { value = "i1p2" },
-- etc
pm = { value = "i1pm" }
},
i2 = {
p1 = { value = "i2p1" },
p2 = { value = "i2p2" },
-- etc
pm = { value = "i2pm" }
},
im = {
p1 = { value = "imp1" },
p2 = { value = "imp2" },
-- etc
pm = { value = "impm" }
}
} --(inner tables)
In another way each group of data is indexed by two variables i&p,I am sure that the data is kept correctly but I want a way to print the data from their tables because I won't know the values of i and p to iterate over them or even the numbers n & m any body know how to do this with lua?
If you know the depth of your nested (inner) tables, you can iterate explicitly to that depth:
for k1,v1 in pairs(t) do
for k2,v2 in pairs(v1) do
for k3, v3 in pairs(v2) do
print(k3, ":", v3)
end
end
end
Alternatively, you can recursively iterate into your nested structure:
function print_tbl(tbl)
if type(tbl) == "table" then
for _,v in pairs(tbl) do
print_tbl(v)
end
else
print(tbl)
end
end
print_tbl(t)
This is just an example. If your tables contain functions, contains userdata, or your nesting has cycles, you'll need a different approach. Take a look at table serialization on the Lua user wiki. Serialization requires sensible handling of tables with nesting, functions, cycles, etc. You may be able to use lessons learned on your data.

Resources