Inserting and removing table element in Lua - lua

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.

Related

Generating all combinations from a table in Lua

I'm trying to iterate through a table with a variable amount of elements and get all possible combinations, only using every element one time. I've landed on the solution below.
arr = {"a","b","c","d","e","f"}
function tablelen(table)
local count = 0
for _ in pairs(table) do
count = count + 1
end
return count
end
function spellsub(table,start,offset)
local str = table[start]
for i = start+offset, (tablelen(table)+1)-(start+offset) do
str = str..","..table[i+1]
end
return str
end
print(spellsub(arr,1,2)) -- Outputs: "a,d,e" correctly
print(spellsub(arr,2,2)) -- Outputs: "b" supposed to be "b,e,f"
I'm still missing some further functions, but I'm getting stuck with my current code. What is it that I'm missing? It prints correctly the first time but not the second?
A solution with a coroutine iterator called recursively:
local wrap, yield = coroutine.wrap, coroutine.yield
-- This function clones the array t and appends the item new to it.
local function append (t, new)
local clone = {}
for _, item in ipairs (t) do
clone [#clone + 1] = item
end
clone [#clone + 1] = new
return clone
end
--[[
Yields combinations of non-repeating items of tbl.
tbl is the source of items,
sub is a combination of items that all yielded combination ought to contain,
min it the minimum key of items that can be added to yielded combinations.
--]]
local function unique_combinations (tbl, sub, min)
sub = sub or {}
min = min or 1
return wrap (function ()
if #sub > 0 then
yield (sub) -- yield short combination.
end
if #sub < #tbl then
for i = min, #tbl do -- iterate over longer combinations.
for combo in unique_combinations (tbl, append (sub, tbl [i]), i + 1) do
yield (combo)
end
end
end
end)
end
for combo in unique_combinations {'a', 'b', 'c', 'd', 'e', 'f'} do
print (table.concat (combo, ', '))
end
For a tables with consecutive integer keys starting at 1 like yours you can simply use the length operator #. Your tablelen function is superfluous.
Using table as a local variable name shadows Lua's table library. I suggest you use tbl or some other name that does not prevent you from using table's methods.
The issue with your code can be solved by printing some values for debugging:
local arr = {"a","b","c","d","e","f"}
function spellsub(tbl,start,offset)
local str = tbl[start]
print("first str:", str)
print(string.format("loop from %d to %d", start+offset, #tbl+1-(start+offset)))
for i = start+offset, (#tbl+1)-(start+offset) do
print(string.format("tbl[%d]: %s", i+1, tbl[i+1]))
str = str..","..tbl[i+1]
end
return str
end
print(spellsub(arr,1,2)) -- Outputs: "a,d,e" correctly
print(spellsub(arr,2,2)) -- Outputs: "b" supposed to be "b,e,f"
prints:
first str: a
loop from 3 to 4
tbl[4]: d
tbl[5]: e
a,d,e
first str: b
loop from 4 to 3
b
As you see your second loop does not ran as the start value is already greater than the limit value. Hence you only print the first value b
I don't understand how your code is related to what you want to achieve so I'll leave it up to you to fix it.

Check for identical elements in a table in Lua?

How would you check a table for three identical elements (looking for three L's)?
table = {nil, nil, L, nil, L} -> false
table = {L, L, nil, nil, L} -> true
Really would appreciate some help!
EDIT: Ok I've got this, but it only outputs false even when there are three or more L's (and does so five times for every check?). Sorry if it seemed like I was trying to get the code for it, I'm genuinely trying to learn! :)
for k, v in pairs( threeL_table ) do
local count = 0
if k == 'L' then
count = count + 1
end
if count == 3 then
print('true')
else
print('false')
end
end
You were almost there. You need to test the values v against 'L', not the keys k. Also, I suppose you want to print the message only once after the scan is concluded; if so, put the if-statement outside of the for-loop. (In this case, you should define count outside of the for-loop, too, otherwise you would not see it once it has ended).
local count = 0
for k, v in pairs( threeL_table ) do
if v == 'L' then -- you need to check for the values not the keys
count = count + 1
end
end
if count == 3 then -- move this out of the for-loop
print('true')
else
print('false')
end
I will not give you any code as you did not show any own efforts to solve the problem.
How would you check a table for three identical elements? Well you count them.
Loop over the table and for every distinct value you create a new counter. You could use another table for that. Once one of those counters reaches 3 you know that you have three identical values.
Another way to solve this.
function detectDup(t,nDup)
table.sort(t)
local tabCount = {}
for _,e in ipairs(t) do
tabCount[e] = (tabCount[e] or 0) + 1
if tabCount[e] >= 3 then
print("The element '" .. e .. "' has more than 3 repetitions!")
return true
end
end
return false
end
print(detectDup({'L', 'L','A','B'},3))
print(detectDup({'L', 'L','A','B','L',},3))

How to initialize table size in lua

What is the most efficient way to convert number to table? Or is it possible to make a table without loops?
local t = 10 -- given number
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} -- result
Update: the t variable is mutable number and I want to for each the value.
t = 3
function foreach(f, t)
for i, v in ipairs(t) do
f(v)
end
end
foreach(print, t)
1
2
3
I need a just the quickest way of new Array(n) in Lua. Or doesn't make any sense?
Maybe you don't know how to answer #Sebastian's question. Here are a few alternatives to get you thinking.
Since your table has only computed elements, you could omit the storage and just perform the calculation on every read access (index operation).
local function newArray(size)
local t = {}
setmetatable(t, {
__index = function (_, i)
return i >= 1 and i <= size and i or nil end})
return t
end
t10 = newArray(10)
for i = 0, 11 do -- ipairs won't work as expected with such a table
print(i, t10[i])
end
t10[2] = "stored values override __index"
print(t10[2])
Of course, you could also replace the table with just an identity function that returns the value, or even just an identity expression. But, maybe you have an unexpressed requirement for a table or you need ipairs to iterate over the sequence.
Speaking of iterators,
local function seq_itor(first, last)
local i = first - 1
return function ()
i = i + 1
if i <= last then return i end
end
end
for i in seq_itor(1, 10) do
print(i)
end
The simplest way to do that would be to define a function:
function newArray(size)
local t = {}
for i = 1, size do
t[i] = i
end
return t
end

Lua Array shuffle not working

I was working on a script to randomize the data inside of my array but I get and error
that says
unexpected symbol near "#"
When I go to that line, and I remove the "#" I get
attempt to perform arithmetic on local `n' (a table value)
Here is my shuffle function
function shuffle(array)
local array = array
local n = #array
local j
local random = math.random
for i=n-1, 1, -1 do
j = random(i)
array[j],array[i] = array[i],array[j]
end
return array
end
and here is what I am trying to randomize
shuffle(new_players)
for name,character in pairs(new_players) do
if (character.inside == true and character.death == 0) then
local player = getPlayerByName(name, map_copy)
if (player ~= nil) then
addState(player)
break
end
end
end
Here is my array
new_players= { }
new_players[charName] = { death = 0, inside= true }
Any help? If i am doing something completely wrong?
1) Try change charName from string to a number.
2) For shuffle you can use this code:
function swap(array, index1, index2)
array[index1], array[index2] = array[index2], array[index1]
end
function shuffle(array)
local counter = #array
while counter > 1 do
local index = math.random(counter)
swap(array, index, counter)
counter = counter - 1
end
end
If your Lua version is < 5.1 then there is no # operator. Use table.getn instead:
local n = table.getn(array);
(Update) Note that your function, while it does shuffle the items around, it does not really shuffle all elements. Also since you reduce the range with each iteration, you will almost certainly swap the first 10% of your array around multiple times. Now swapping them multiple times is not bad by itself, but that you are, by comparison, almost never swapping the other elements is.
So one option to solve this would be to always use the same range for your random variable. And I would go even further and select two random indexes to swap:
function shuffle(array)
local n, random, j = table.getn(array), math.random
for i=1, n do
j,k = random(n), random(n)
array[j],array[k] = array[k],array[j]
end
return array
end
The other option would be to select random elements from the source array and put them into a new output array:
local rnd,trem,getn,ins = math.random,table.remove,table.getn,table.insert;
function shuffle(a)
local r = {};
while getn(a) > 0 do
ins(r, trem(a, rnd(getn(a))));
end
return r;
end

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