I understand, "for i, v" loops for tables, i is the index, and v is the value, but what does this script do? I do not think this has anything to do with tables, but the only type of for table loops I know in ROBLOX script is the first one I mentioned; "for i, v" loops, which loop through tables.
randomVariable = 1
for i = 1, randomVariable do
(random script)
end
This is a numeric loop statement.
for controlValue = startValue, endValue, stepValue do
-- for body
end
It goes from startValue until it reaches endValue, after running body code, controlValue is increased by stepValue. If controlValue is higher or equals to endValue the loop stops. If stepValue is not provided, it equals to 1.
It's equivalent to this code:
local controlValue = startValue
if not stepValue then stepValue = 1 end -- if no stepValue it equals to 1
while controlValue < endValue do
-- for body
controlValue = controlValue + stepValue
end
There are a few different ways to loop in Lua.
while variable < number do
repeat stuff until variable == number
for key, value in pairs do
for index, value in ipairs do
for i = 1, number do
i = 1 is the initial condition.
It usually begins at one, then loops through items in a table.
So you can think of it as an index in that regard.
where the randomVariable you mentioned would be #tab
however, you could set that initial condition to be larger, then count down.
for i = #tab, 1, -1 do
the third, optional argument is called "step size"
and it's the amount that initial condition is changed, after completing each loop. it defaults to 1, so it's not needed, most of the time.
so to step through all the even numbers in a table it would be
for i = 2, #tab, 2 do
Further reading: https://www.tutorialspoint.com/lua/lua_loops.htm
I don't understand why the following code produces error.
The code begins with the main() function at the bottom.
heads = {}
function push(t)
if (#t == 2) then
table.insert(heads, t)
end
end
function remove(id)
for i = 1, #heads do
if (heads[i][2] == id) then
table.remove(heads, i)
end
end
end
function main()
push({50, 1})
push({50, 2})
push({50, 3})
remove(2)
end
When I run the code, I get attempt to index a nil value (field '?') error.
I expect to push the subtable elements into the table and then remove only the second one. So the resulting elements can be {50, 1} and {50, 3}.
Why is my code not working and how to fix this?
Andrew got it right. Never try to remove a value inside a table when you iterate the table. This is a common issue in many languages. Usually, you would store the value first and then remove like so:
local e
for i = 1, #heads do
if (heads[i][2] == id) then
e = i
end
end
if e then table.remove(heads, e) end
However, this solution is slow. Simply use the ID as key of your table:
local heads = {}
heads[1] = 50 -- push
heads[2] = 50
heads[3] = 50
heads[2] = nil -- remove
No need for unnecessary function calls and iterations.
According to 5.1 manual table.remove "Removes from table the element at position, shifting down other elements to close the space, if necessary"
size of heads (#heads) is calculated once before loop execution, when i==2 you call table.remove, and so size of the table shrinks to 2, and on next iteration you try index heads[3][2], but heads[3] is nil, therefore "attempt to index a nil value" error message.
As Andrew mentioned, for i = 1, #heads do will go to the original length of the list; if you shorten heads during the loop, then the final iteration(s) will read heads[i] and find only nil.
A simple way to fix this is to move backwards through the list, since removing an element only affects indices after the index you have removed from:
for i = #heads, 1, -1 do
if heads[i][2] == id then
table.remove(heads, i)
end
end
Note that in any case, this is O(n*d) complexity and could be very slow if you are deleting many elements from the list. And, as others pointed out, there's a O(1) approach where you use a map from v[1] => v instead.
To avoid problems caused by removing fields while iterating over an array, I've used a while loop with an index variable, which is incremented at the end of each iteration, but decremented when an index is removed. So, for instance, to remove all elements with an even index:
local t = { 1, 2, 3, 4, 5 }
local i = 1
while t[i] do
if t[i] % 2 == 0 then
table.remove(t, i)
i = i - 1
end
i = i + 1
end
This method allows you to iterate over array indices in ascending order.
Addressing this iteration, in case of many items that are to be removed, I'd rather go for
local result = {}
for _, v in ipairs(myTab) do
if v == 'nice' then
table.insert(result, v)
end
end
myTab = result
as table.remove is slow when shifting many elements.
This question already has answers here:
Why does Lua's length (#) operator return unexpected values?
(2 answers)
Closed 6 years ago.
I am new to lua and my lua version is 5.1.
I've got this problem. Can anybody help me to explain '#'?
local tblTest =
{
[1] = 2,
[2] = 5,
[5] = 10,
}
print(#tblTest)
this output 2 and ..
local tblTest =
{
[1] = 2,
[2] = 5,
[4] = 10,
}
print(#tblTest)
output is 4. Why?
thanks all of u.
The output is 4 because the last key with a value is 4 but that doesn't mean that 3 isn't also defined. In lua 3 would be defined as nil. So when you use the # operator it counts every key in a sequence with a value until the last non-nil value. Except,(and I could be wrong about this) the last key in the table is a power of 2, which do to language optimization, it counts up to the value that is a power of 2. In general you should stay away from tables with nil values as there are some other weird behaviors that happen because of this.
This chunk with do what you want though:
local T = {
[1] = 2,
[2] = 5,
[10] = 10
}
local lengthNum = 0
For k, v in pairs(T) do -- for every key in the table with a corresponding non-nil value
lengthNum = lengthNum + 1
end
print(lengthNum)
}
What this does is it checks the entire table for keys (such as [1] or [2]) and checks if they have value. Every key with a non-nil value runs the for loop one more time. There might be a shorter way to this, but this is how I would do it.
Okay, so I've got a strange problem with the following Lua code:
function quantizeNumber(i, step)
local d = i / step
d = round(d, 0)
return d*step
end
bar = {1, 2, 3, 4, 5}
local objects = {}
local foo = #bar * 3
for i=1, #foo do
objects[i] = bar[quantizeNumber(i, 3)]
end
print(#fontObjects)
After this code has been run, the length of objects should be 15, right? But no, it's 4. How is this working and what am I missing?
Thanks, Elliot Bonneville.
Yes it is 4.
From the Lua reference manual:
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
Let's modify the code to see what is in the table:
local objects = {}
local foo = #bar * 3
for i=1, foo do
objects[i] = bar[quantizeNumber(i, 3)]
print("At " .. i .. " the value is " .. (objects[i] and objects[i] or "nil"))
end
print(objects)
print(#objects)
When you run this you see that objects[4] is 3 but objects[5] is nil. Here is the output:
$ lua quantize.lua
At 1 the value is nil
At 2 the value is 3
At 3 the value is 3
At 4 the value is 3
At 5 the value is nil
At 6 the value is nil
At 7 the value is nil
At 8 the value is nil
At 9 the value is nil
At 10 the value is nil
At 11 the value is nil
At 12 the value is nil
At 13 the value is nil
At 14 the value is nil
At 15 the value is nil
table: 0x1001065f0
4
It is true that you filled in 15 slots of the table. However the # operator on tables, as defined by the reference manual, does not care about this. It simply looks for an index where the value is not nil, and whose following index is nil.
In this case, the index that satisfies this condition is 4.
That is why the answer is 4. It's just the way Lua is.
The nil can be seen as representing the end of an array. It's kind of like in C how a zero byte in the middle of a character array is actually the end of a string and the "string" is only those characters before it.
If your intent was to produce the table 1,1,1,2,2,2,3,3,3,4,4,4,5,5,5 then you will need to rewrite your quantize function as follows:
function quantizeNumber(i, step)
return math.ceil(i / step)
end
The function quantizeNumber is wrong. The function you're looking for is math.fmod:
objects[i] = bar[math.fmod(i, 3)]
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