Lua Nested Table Getting Elements - lua

I have a nested table like so:
t1 ={}
t1[1] = {col1=1,col2=1,col3=1,col4=1}
t1[2] = {col1=1,col2=1,col3=1,col4=1}
t1[3] = {col1=1,col2=1,col3=1,col4=1}
t1[4] = {col1=1,col2=1,col3=1,col4=1}
it's actually much larger with 250 items in t1 and 30 items per nested table so what I want to do is loop through and get sub table values like this:
for i = 2, 4 do
local width = t1[draw.ID].col1 --draw.ID is got elsewhere
end
but changing the number part of .col1 to the i part so when it loops through it gets:
t1[draw.ID].col2
t1[draw.ID].col3
t1[draw.ID].col4
I'm using Lua 5.1.

for i= 2, 4 do
local width = t1[draw.ID]["col" .. i] --draw.ID is got elsewhere
end

Ideally, col would be or would contain an array-like table or sequence. This is a much more scalable way to accomplish what you're trying to do. String concatenation ['col' .. i] to access table keys in the fashion that you'd access them as an array is costly and unnecessary, if it can be avoided. This is especially important if this is something you plan to do often and want to work quickly.
-- Elements of t1 contain tables with cols.
local t1 = {}
t1[1] = {cols = {1,1,1,1}}
t1[2] = {cols = {1,1,1,1}}
t1[3] = {cols = {1,1,1,1}}
t1[4] = {cols = {1,1,1,1}}
for i=2, 4 do
local width = t1[draw.ID].cols[i]
end
-- Elements of t1 are the cols.
local t1 = {}
t1[1] = {1,1,1,1}
t1[2] = {1,1,1,1}
t1[3] = {1,1,1,1}
t1[4] = {1,1,1,1}
for i=2, 4 do
local width = t1[draw.ID][i]
end
Edit: If it's unavoidable that you have to use table keys in the style of ['col' .. i], then the best you could do is to cache them for faster access.
-- Cache all the possible keys that you'll need.
local colkeys = {}
for i=1, 30 do colkeys[i] = 'col' .. i end
for i=2, 4 do
local width = t1[draw.ID][colkeys[i]]
end
This method is anywhere from 4 to 8 times faster than concatenating a string each time that you need to index the table. It's not the ideal solution, but it works if you're stuck with the likes of col1 to col30.

Related

/Lua/ How to do this (idk how to call that lol)

I need to make a trolleybus number, which won't repeat for game. For example, there is a number "101" and there musn't be more "101". How to do that? I have a code, but I know, he won't work and I won't test it lol
function giveNumber()
local number = math.random(100, 199)
local takedNumbers = {}
local i = 0
local massiv = i+1
script.Parent.pered.SurfaceGui.TextLabel.Text = number
script.Parent.zad.SurfaceGui.TextLabel.Text = number
script.Parent.levo.SurfaceGui.TextLabel.Text = number
script.Parent.pravo.SurfaceGui.TextLabel.Text = number
takedNumbers[massiv] = {number}
end
script.Parent.Script:giveNumber() // what I wrote here? idk...
if number == takedNumbers[massiv] then
giveNumber()
end
i didn't test it, because I think it won't work because this code is something bad
I think this will serve your needs.
In the function generateUniqueNumber, the script loops until it found a number that is not yet in the array. (in other words, that it hasn't given out yet)
Once it found that number, it will insert it into the table to remember that it has given it out, and then it will return the number.
Then on the bottom of the script we just give the numbers to the buses :-)
--[[
Goal: Give all buses a unique number
]]
-- Variables
local takenNumbers = {};
-- This function returns a random number in the range [100, 199] that has not been taken yet
function generateUniqueNumber()
local foundNumber = false;
while not foundNumber do
randomNumber = math.random(100, 199);
if not table.find(takenNumbers, randomNumber) then
table.insert(takenNumbers, randomNumber);
return randomNumber;
end
end
end
-- This function sets the number of the bus
script.Parent.pered.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.zad.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.levo.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.pravo.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
2 things:
I didn't test this code as Roblox is not installed on the pc I'm currently on.
Please try formatting your code nicely next time. It greatly improves the readability! For example, you can use this website:
https://codebeautify.org/lua-beautifier
Simpler
Fill a table with free numbers...
local freenumbers = {}
for i = 1, 99 do freenumbers[i] = i + 100 end
...for every new takennumbers use table.remove() on freenumbers
local takennumbers = {}
if #freenumbers > 0 then
takennumbers[#takennumbers + 1] = table.remove(freenumbers, math.random(1, #freenumbers))
end

save strings in lua table

Does someone know a solution to save the key and the values to an table? My idea does not work because the length of the table is 0 and it should be 3.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
a = {}
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a)
The output is correct.
run for k,v in pairs(a) do print(k,v) end to check the contents of your table.
The problem is the length operator which by default cannot be used to get the number of elements of any table but a sequence.
Please refer to the Lua manual: https://www.lua.org/manual/5.4/manual.html#3.4.7
When t is a sequence, #t returns its only border, which corresponds to
the intuitive notion of the length of the sequence. When t is not a
sequence, #t can return any of its borders. (The exact one depends on
details of the internal representation of the table, which in turn can
depend on how the table was populated and the memory addresses of its
non-numeric keys.)
Only use the length operator if you know t is a sequence. That's a Lua table with integer indexes 1,..n without any gap.
You don't have a sequence as you're using non-numeric keys only. That's why #a is 0
The only safe way to get the number of elements of any table is to count them.
local count = 0
for i,v in pairs(a) do
count = count + 1
end
You can put #Piglet' code in the metatable of a as method __len that is used for table key counting with length operator #.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
local a = setmetatable({},{__len = function(tab)
local count = 0
for i, v in pairs(tab) do
count = count + 1
end
return count
end})
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a) -- puts out: 3
The output of #a with method __len even is correct if the table holds only a sequence.
You can check this online in the Lua Sandbox...
...with copy and paste.
Like i do.

What does [{n,{}}] do in lua?

As you can tell I'm a beginner in lua. I am trying to understand a function I'm stuck at what the following code segment does?
It is used in the following code snippet in the last line:
function classify(txt_dir, img_dir, cls_list)
local acc = 0.0
local total = 0.0
local fea_img = {}
local fea_txt = {}
for fname in io.lines(cls_list) do
local imgpath = img_dir .. '/' .. fname .. '.t7'
local txtpath = txt_dir .. '/' .. fname .. '.t7'
fea_img[#fea_img + 1] = extract_img(imgpath)
fea_txt[#fea_txt + 1] = extract_txt(txtpath)
end
for i = 1,#fea_img do
-- loop over individual images.
for k = 1,fea_img[i]:size(1) do
local best_match = 1
local best_score = -math.huge
for j = 1,#fea_txt do
local cur_score = torch.dot(fea_img[i][{k,{}}], fea_txt[j])
From my understanding, fea_img is a lua table. Is the line fea_img[i][{k,{}}] some sort of slicing for the value for the key 'i' in the table fea_img?
I tried searching for more examples and found this being used here too (last line):
for i = 1,nsamples,batchsize do
-- indices
local lasti = math.min(i+batchsize-1,nsamples)
local m = lasti - i + 1
-- k-means step, on minibatch
local batch = x[{ {i,lasti},{} }]
Any help on this would be really appreciated. Thank you!
In lua you can access a specific index on a table in multiple ways. Like these two examples
local myValue = someTable.theIndex
-- or
local myOtherValue = someTable[2]
So the construct you see here is to access some values from a (nested) table.
Also in lua you can use anything except nil as a index, so even tables are possible.
The line
fea_img[i][{k,{}}]
Can be extended to this:
local index1 = i -- i in this case is your loop variable
local index2 = { k , { } } -- This creates a table with 2 values, the first one will be the vaule of the var k, the second one is an empty table
local value1 = fea_img[index1] -- This will get you a table
local value2 = value1[index2] -- This will get the same as: fea_img[i][{k,{}}]
Correction and Addition:
As Nicol Bolas already said in the comments: The index must be an exact match. Which means it literally has to be the same table, which is not the case for the presented code from you. Either you dropped code you thought is unnecessary or fea_img has some some kind of metatable on it.
In the case of
local k = 2
local table1 = {k, { } }
local table2 = {k, { } }
table2 and table1 do have the exact same content. But they are not the same table. Which will lead to nil always being retrieved if one is used to store data in a table and the other is used to get it back.
Syntactically, t[k] is indexing a table with a key. Normally, if there is a record in the table with the key k, its value is returned. Nothing more, nothing less.
If fea_img[i] was a normal table, {k,{}} would always return nil, since table indices are resolved based on their identity ({k,{}} is always a new table). Based on your code, I have to conclude that the elements of fea_img (i.e. what extract_img returns) are not normal tables.
In Lua, you can override the indexing operation using a metatable. If you index a value that has a metatable with __index, it will be used if there is no matching record in the table:
local t = {}
setmetatable(t, {
__index = function(t, k)
return k
end
})
print(t[{}])
This table has a metatable associated with it, which is used in the indexing operation. In this case __index returns the key, but whatever library you are using might provide more complex behaviour.
This is specific to the library you are using, not something related to the Lua syntax.

Randomly select a key from a table in Lua

I want to randomly populate a grid in Lua using a list of possible items, which is defined as follows:
-- Items
items = {}
items.glass = {}
items.glass.color = colors.blue
items.brick = {}
items.brick.color = colors.red
items.grass = {}
items.grass.color = colors.green
So the keys of the table are "glass", "brick" and "grass".
How do I randomly select one of these keys if they are not addressable by a numeric index?
Well, I kind of got a workaround, but I would be open to any better suggestions.
The first solution consists of having a secondary table which serves as an index to the first table:
item_index = {"grass", "brick", "glass"}
Then I can randomly store a key of this table (board is a matrix that stores the value of the random entry in item_index):
local index = math.random(1,3)
board[i][j] = item_index[index]
After which I can get details of the original list as follows:
items[board[y][x]].color
The second solution, which I have decided on, involves adding the defined elements as array elements to the original table:
-- Items
items = {}
items.glass = {}
items.glass.color = colors.blue
table.insert(items, items.glass) --- Add item as array item
items.brick = {}
items.brick.color = colors.red
table.insert(items, items.brick) --- Add item as array item
items.grass = {}
items.grass.color = colors.green
table.insert(items, items.grass) --- Add item as array item
Then, I can address the elements directly using an index:
local index = math.random(1,3)
board[i][j] = items[index]
And they can be retrieved directly without the need for an additional lookup:
board[y][x].color
Although your second method gives concise syntax, I think the first is easier to maintain. I can't test here, but I think you can get the best of both, won't this work:
local items = {
glass = {
color = colors.blue,
},
brick = {
color = colors.red,
},
grass = {
color = colors.green,
},
}
local item_index = {"grass", "brick", "glass"}
local index = math.random(1,3)
board[i][j] = items[item_index[index]]
print('color:', board[i][j].color)
If you're table is not too big and you can just break off at a random point. This method assumes that you know the number of entries in the table (which is not equal to #table value, if the table has non-number keys).
So find the length of the table, then break at random(1, length(table)), like so:
local items = {} ....
items.grass.color = colors.green
local numitems = 0 -- find the size of the table
for k,v in pairs(items) do
numitems = numitems + 1
end
local randval = math.random(1, numitems) -- get a random point
local randentry
local count = 0
for k,v in pairs(items) do
count = count + 1
if(count == randentry) then
randentry = {key = k, val = v}
break
end
end
The goods: You don't have to keep track of the keys. It can be any table, you don't need to maintain it.
The bad and ugly: It is O(n) - two linear passes.So, it is not at all ideal if you have big table.
The above answers assume you know what all of the keys are, which isn't something I was able to do earlier today. My solution:
function table.randFrom( t )
local choice = "F"
local n = 0
for i, o in pairs(t) do
n = n + 1
if math.random() < (1/n) then
choice = o
end
end
return choice
end
Explanation: we can't use table.getn( t ) to get the size of the table, so we track it as we go. The first item will have a 1/1=1 chance of being picked; the second 1/2 = 0.5, and so on...
If you expand for N items, the Nth item will have a 1/N chance of being chosen. The first item will have a 1 - (1/2) - (1/3) - (1/4) - ... - (1/N) chance of not being replaced (remember, it is always chosen at first). This series converges to 1 - (N-1)/N = 1/N, which is equal to the chance of the last item being chosen.
Thus, each item in the array has an equal likelihood of being chosen; it is uniformly random. This also runs in O(n) time, which isn't great but it's the best you can do if you don't know your index names.

Concatenation of tables in Lua

ORIGINAL POST
Given that there is no built in function in Lua, I am in search of a function that allows me to append tables together. I have googled quite a bit and have tried every solutions I stumbled across but none seem to work properly.
The scenario goes like this: I am using Lua embeded in an application. An internal command of the application returns a list of values in the form of a table.
What I am trying to do is call that command recursively in a loop and append the returned values, again in the form of a table, to the table from previous iterations.
EDIT
For those who come across this post in the future, please note what #gimf posted. Since Tables in Lua are as much like arrays than anything else (even in a list context), there is no real correct way to append one table to another. The closest concept is merging of tables. Please see the post, "Lua - merge tables?" for help in that regard.
Overcomplicated answers much?
Here is my implementation:
function TableConcat(t1,t2)
for i=1,#t2 do
t1[#t1+1] = t2[i]
end
return t1
end
If you want to concatenate an existing table to a new one, this is the most concise way to do it:
local t = {3, 4, 5}
local concatenation = {1, 2, table.unpack(t)}
Although I'm not sure how good this is performance-wise.
And one more way:
for _,v in ipairs(t2) do
table.insert(t1, v)
end
It seems to me the most readable one - it iterates over the 2nd table and appends its values to the 1st one, end of story. Curious how it fares in speed to the explicit indexing [] above
A simple way to do what you want:
local t1 = {1, 2, 3, 4, 5}
local t2 = {6, 7, 8, 9, 10}
local t3 = {unpack(t1)}
for I = 1,#t2 do
t3[#t1+I] = t2[I]
end
To add two tables together do this
ii=0
for i=#firsttable, #secondtable+#firsttable do
ii=ii+1
firsttable[i]=secondtable[ii]
end
use the first table as the variable you wanted to add as code adds the second one on to the end of the first table in order.
i is the start number of the table or list.
#secondtable+#firsttable is what to end at.
It starts at the end of the first table you want to add to, and ends at the end of the second table in a for loop so it works with any size table or list.
In general the notion of concatenating arbitrary tables does not make sense in Lua because a single key can only have one value.
There are special cases in which concatenation does make sense. One such is for tables containing simple arrays, which might be the natural result of a function intended to return a list of results.
In that case, you can write:
-- return a new array containing the concatenation of all of its
-- parameters. Scaler parameters are included in place, and array
-- parameters have their values shallow-copied to the final array.
-- Note that userdata and function values are treated as scalar.
function array_concat(...)
local t = {}
for n = 1,select("#",...) do
local arg = select(n,...)
if type(arg)=="table" then
for _,v in ipairs(arg) do
t[#t+1] = v
end
else
t[#t+1] = arg
end
end
return t
end
This is a shallow copy, and makes no attempt to find out if a userdata or function value is a container or object of some kind that might need different treatment.
An alternative implementation might modify the first argument rather than creating a new table. This would save the cost of copying, and make array_concat different from the .. operator on strings.
Edit: As observed in a comment by Joseph Kingry, I failed to properly extract the actual value of each argument from .... I also failed to return the merged table from the function at all. That's what I get for coding in the answer box and not testing the code at all.
If you want to merge two tables, but need a deep copy of the result table, for whatever reason, use the merge from another SO question on merging tables plus some deep copy code from lua-users.
(edit
Well, maybe you can edit your question to provide a minimal example... If you mean that a table
{ a = 1, b = 2 }
concatenated with another table
{ a = 5, b = 10 }
should result in
{ a = 1, b = 2, a = 5, b = 10 }
then you're out of luck. Keys are unique.
It seems you want to have a list of pairs, like { { a, 1 }, { b, 2 }, { a, 5 }, { b, 10 } }. You could also use a final structure like { a = { 1, 5 }, b = { 2, 10 } }, depending on your application.
But the simple of notion of "concatenating" tables does not make sense with Lua tables.
)
Here is an implementation I've done similar to RBerteig's above, but using the hidden parameter arg which is available when a function receives a variable number of arguments. Personally, I think this is more readable vs the select syntax.
function array_concat(...)
local t = {}
for i = 1, arg.n do
local array = arg[i]
if (type(array) == "table") then
for j = 1, #array do
t[#t+1] = array[j]
end
else
t[#t+1] = array
end
end
return t
end
Here is my implementation to concatenate a set of pure-integer-indexing tables, FYI.
define a function to concatenate two tables, concat_2tables
another recursive function concatenateTables: split the table list by unpack, and call concat_2tables to concatenate table1 and restTableList
t1 = {1, 2, 3}
t2 = {4, 5}
t3 = {6}
concat_2tables = function(table1, table2)
len = table.getn(table1)
for key, val in pairs(table2)do
table1[key+len] = val
end
return table1
end
concatenateTables = function( tableList )
if tableList==nil then
return nil
elseif table.getn(tableList) == 1 then
return tableList[1]
else
table1 = tableList[1]
restTableList = {unpack(tableList, 2)}
return concat_2tables(table1, concatenateTables(restTableList))
end
end
tt = {t1, t2, t3}
t = concatenateTables(tt)
-- Lua 5.1+
function TableAppend(t1, t2)
-- A numeric for loop is faster than pairs, but it only gets the sequential part of t2
for i = 1, #t2 do
t1[#t1 + 1] = t2[i] -- this is slightly faster than table.insert
end
-- This loop gets the non-sequential part (e.g. ['a'] = 1), if it exists
local k, v = next(t2, #t2 ~= 0 and #t2 or nil)
while k do
t1[k] = v -- if index k already exists in t1 then it will be overwritten
k, v = next(t2, k)
end
end
EDIT
Here's a better solution, the other one tended to overwrite numeric keys, the usage is still the same:
function merge(...)
local temp = {}
local index = 1
local result = {}
math.randomseed(os.time())
for i, tbl in ipairs({ ... }) do
for k, v in pairs(tbl) do
if type(k) == 'number' then
-- randomize numeric keys
k = math.random() * i * k
end
temp[k] = v
end
end
for k, v in pairs(temp) do
if type(k) == "number" then
-- Sort numeric keys into order
if result[index] then
index = index + 1
end
k = index
end
result[k] = v
end
return result
end
ORIGINAL
A wee bit late to the game, but this seems to work for me:
function concat(...)
local result = {}
for i, tbl in ipairs({...}) do
for k, v in pairs(tbl) do
if type(k) ~= "number" then
result[k] = v
else
result[i] = v
end
end
end
return result
end
It might be a bit overcomplicated, but it takes an infinite amount of arguments, and works for both key-value pairs and regular "arrays" (numbers as keys). Here's an example
I like the simplicity in #Weeve Ferrelaine answer, but mutations may cause many issues and in general, are not desirable.
Version with NO MUTATION.
---#param t1 {}
---#param t2 {}
function TableConcat(t1,t2)
local tOut = {}
for i = 1, #t1 do
tOut[i] = t1[i]
end
for i = #t1, #t1 + #t2 do
tOut[i] = t2[i]
end
return tOut
end
Original implementation, that's mutating t1.
function TableConcat(t1,t2)
for i=1,#t2 do
t1[#t1+1] = t2[i]
end
return t1
end
Use table.concat:
http://lua-users.org/wiki/TableLibraryTutorial
> = table.concat({ 1, 2, "three", 4, "five" })
12three4five
> = table.concat({ 1, 2, "three", 4, "five" }, ", ")
1, 2, three, 4, five
> = table.concat({ 1, 2, "three", 4, "five" }, ", ", 2)
2, three, 4, five
> = table.concat({ 1, 2, "three", 4, "five" }, ", ", 2, 4)
2, three, 4

Resources