lua - table maintenance (particle system related) - lua

The update() function below gets called on every frame of a game. If the Drop particle has y value greater than 160 I want to remove it from the table. The problem is that I get "attempt to compare number with nil" errors, on the line notated below:
local particles = {};
function update()
local num = math.random(1,10);
if(num < 4) then
local drop = Drop.new()
table.insert ( particles, drop );
end
for i,val in ipairs(particles) do
if(val.y > 160) then --ERROR attempt to compare number with nil
val:removeSelf(); --removeSelf() is Corona function that removes the display object from the screen
val = nil;
end
end
end
What am I doing wrong? Obviously val is nil, but I don't understand why the table iteration would find val in the first place since I set it to nil when it's y value gets larger than 160.

Thanks for the answers, they were all helpful. Here is what ended up working for me. The table.remove call is necessary to keep the loop running properly.
for i = #particles, 1, -1 do
if particles[i].y > 160 then
local child = table.remove(particles, i)
if child ~= nil then
display.remove(child)
child = nil
end
end
end

You're looking in the wrong place, the problem isn't that val is nil, it's val.y that's nil. See this example:
> x=nil
> if x.y > 10 then print("test") end
stdin:1: attempt to index global 'x' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: ?
> x={y=nil}
> if x.y > 10 then print("test") end
stdin:1: attempt to compare number with nil
stack traceback:
stdin:1: in main chunk
[C]: ?
Also, when you set val to nil, that may not be doing anything (I believe val is a copy):
> t={"a", "b", "c", "d"}
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
> for i,val in ipairs(t) do if i==3 then print("delete", val); val=nil end end
delete c
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
Edit: to delete an element from a table, you want table.remove:
> t[3]=nil
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
> t[3]="c"
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
> for i,val in ipairs(t) do if i==3 then print("delete", val); table.remove(t, i) end end
delete c
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 d

JeffK's solution should work, but I think the reason it will work is not because of the fact that he's traversing the list backwards, but because he is setting particles[i] = nil instead of val = nil. If you run val = nil you're only setting the local copy of val to nil, not the entry in the table.
Try this:
for i,val in ipairs(particles) do
if(val.y > 160) then
particles[i]:removeSelf()
particles[i] = nil;
end
end

I don't think you are allowed to modify the contents of a table while ipairs is iterating through it. I vaguely remember reading that my hardcopy of the Lua 5.1 Reference Manual, but I can't seem to locate it now. When you set val to nil, it removes an element from the particles table.
You might try processing the table in reverse, since your function is doing a full sweep of the particles table, conditionally removing some items:
for x = #particles, 1, -1 do
if particles[x].y > 160 then
particles[x]:removeSelf()
particles[x] = nil
end
end

Related

pico8 lua: unexpeted change of size of an array

I am seeing some unexpected behaviour when using a table as an array in pico8 lua when compared to regular PUC-Rio lua
If I run the following code using PUC-Rio lua5.4.4 (ubuntu)
local t={}
for i=1,10 do t[i] = i*10 end
t[2]=nil
t[4]=nil
t[6]=nil
t[8]=nil
print()
for i=1,#t do print(t[i]) end
I get the expected output
10
nil
30
nil
50
nil
70
nil
90
100
However if i run the same code with pico-8 I get:
10
This appears triggered only when I delete (ie set to nil) the t[8] element. if I comment out that line then I get the expected on pico8
10
nil
30
nil
50
nil
70
80
90
100
It appears, in pico8 lua, that the #t size of the array changes to 1 when the t[8] element is set to nil.
Both are expected results, the length operator # in lua returns a number n where t[n] ~= nil and t[n+1] == nil, if there are holes (nil value) inside, the result is undefined.
To find the maximum numeric index, in lua 5.1 you can use table.maxn, in other versions you have to write one.
table.maxn = function(t)
local n = 0
for k, v in pairs(t) do
if type(k) == 'number' and k > n then
n = k
end
end
return n
end
It seem that the size operator #t is just not well defined in lua in the presence of nil values.
https://www.lua.org/pil/19.1.html
"undefined behaviour" in a scripting language.. Nice.

Stack Overflow on Lua metatable

I used to have a construct that worked with luajit:
mytbl = setmetatable({1}, {__index = function(tbl,idx) return tbl[idx - 1] + 1 end})
Now with plain Lua 5.4 this gives me a stack overflow:
> mytbl[1000]
stdin:1: C stack overflow
stack traceback:
stdin:1: in metamethod 'index'
....
The goal is to have a table where the default is to return the index itself:
mytbl[10]
should return 10. But when I say
mytbl[3] = 5
the value of
mytbl[10]
should be 12 (the values from 1 now yield 1,2,5,6,7,8,9,10,11,12,...)
Is there a way to get this in Lua 5.4 without the stack overflow? Or should I create another function for it?
You are accessing the table within the __index. That causes another __index to be called and so on.
Use rawget when you want to access the tbl itself.
If you want to get a custom logic that does not rely on existence of elements, write your function in a way that allows for trailing recursion or write it iteratively without any recursion at all:
__index=function(tbl, idx)
local acc = 0
for i=idx-1, 1, -1 do
local th = rawget(tbl, i)
if th then
return acc + th + 1
else
acc = acc + 1
end
end
return acc
end
This is what I came up with now:
__index=function(tbl, idx)
local max = 0
for k, v in next, tbl do
if k <= idx then max = v - k end
end
return idx + max
end
I only have very few entries in tbl so this should be reasonable fast for my purposes.
My test:
mytbl[5] = 9
for i = 1, 10 do
print(mytbl[i])
end
outputs
1
2
3
4
9
10
11
12
13
14

How to iterate through results in sets?

In my Tabletop Simulator mod I have a bag, when something is dropped in the bag the emptyContents() function is called. For example I can drop 15 dice in the bag.
In the emptyContents() function I iterate over the objects in the bag. But as you can see I have to put in multiple if statements to catch the amount of dice put in because I want the dice to be spawned on different positions.
The contents variable is the amount of dice in the bag.
function emptyContents()
contents = self.getObjects()
for i, _ in ipairs(self.getObjects()) do
if i <= 6 then
self.takeObject(setPosition(5, -3))
elseif i <= 12 then
self.takeObject(setPosition(12.4,-5))
elseif i <= 18 then
self.takeObject(setPosition(19.8,-7))
end
end
end
How can I make the function less static? Because now I need to write if statements for each set of 6 dice.
maybe you can add a config like this:
local t = {
{6, 5, -3},
{12, 12.4, -5},
{18, 19.8, -7},
}
function emptyContents()
contents = self.getObjects()
for i, _ in ipairs(self.getObjects()) do
for _, v in ipairs(t) do
local l, p1, p2 = unpack(v)
if i <= l then
self.takeObject(setPosition(p1, p2))
break
end
end
end
end

How to implement combinations tail-recursively?

I'm teaching myself Lua by reading Ierusalimschy's Programming in Lua (4th edition), and doing the exercises. Exercise 6.5 is
Write a function that takes an array and prints all combinations of the elements in the array.
After this succinct statement the book gives a hint that makes it clear that what one is expected to do is to write a function that prints all the C(n, m) combinations of m elements from an array of n elements.
I implemented the combinations function shown below:
function combinations (array, m)
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (array, m, prefix)
local n = #array
if n < m then
return
elseif m == 0 then
print(table.unpack(prefix))
return
else
local deleted = {table.unpack(array, 2, #array)}
_combinations(deleted, m - 1, append(prefix, array[1]))
_combinations(deleted, m, prefix)
end
end
_combinations(array, m, {})
end
It works OK, but it is not tail-recursive.
Can someone show me a tail-recursive function that does the same thing as combinations above does?
(For what it's worth, I am using Lua 5.3.)
NB: I realize that the exercise does not require that the function be tail-recursive. This is a requirement I have added myself, out of curiosity.
EDIT: I simplified the function slightly, but removing a couple of nested functions that were not adding much.
There is a third option, one that doesn't have a snake eating it's tail. Although recursion with tail-calls don't lead to stack overflow, I avoid doing so out of personal preference. I use a while loop and a stack that holds the information for each iteration. Within the loop you pop the next task from the stack, do the work, then push next task onto the stack. I feel it looks cleaner and it's easier to visualize the nesting.
Here is how I would translate your code into the way I would write it:
function combinations(sequence, item)
local function append(array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local stack = {}
local node = { sequence, item, {} }
while true do
local seq = node[ 1 ]
local itm = node[ 2 ]
local pre = node[ 3 ]
local n = #seq
if itm == 0 then
print(table.unpack(pre))
elseif n < itm then
-- do nothing
else
local reserve = {table.unpack(seq, 2, #seq)}
table.insert(stack, { reserve, itm, pre })
table.insert(stack, { reserve, itm-1, append(pre, seq[ 1 ]) })
end
if #stack > 0 then
node = stack[ #stack ] -- LIFO
stack[ #stack ] = nil
else
break
end
end
end
You can use this while-loop stack/node technique for just about any recursive method. Here is an example where it's applied to printing deeply nested tables: https://stackoverflow.com/a/42062321/5113346
My version, using your input example gives the same output:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5.
Forgive me if it doesn't work with other passed params because I didn't try to solve the answer to the exercise but rather just rewrite the code in your original post.
OK, I think I found one way to do this:
function combinations (array, m)
local dropfirst = function (array)
return {table.unpack(array, 2, #array)}
end
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (sequence, m, prefix, queue)
local n = #sequence
local newqueue
if n >= m then
if m == 0 then
print(table.unpack(prefix))
else
local deleted = dropfirst(sequence)
if n > m then
newqueue = append(queue, {deleted, m, prefix})
else
newqueue = queue
end
return _combinations(deleted, m - 1,
append(prefix, sequence[1]),
newqueue)
end
end
if #queue > 0 then
newqueue = dropfirst(queue)
local newargs = append(queue[1], newqueue)
return _combinations(table.unpack(newargs))
end
end
_combinations(sequence, m, {}, {})
end
This version is, I think, tail-recursive. Unfortunately, it does not print out the results in as nice an order as did my original non-tail-recursive version (not to mention the added complexity of the code), but one can't have everything!
EDIT: Well, no, one can have everything! The version below is tail-recursive, and prints its results in the same order as does the original non-tail-recursive version:
function combinations (sequence, m, prefix, stack)
prefix, stack = prefix or {}, stack or {}
local n = #sequence
if n < m then return end
local newargs, newstack
if m == 0 then
print(table.unpack(prefix))
if #stack == 0 then return end
newstack = droplast(stack)
newargs = append(stack[#stack], newstack)
else
local deleted = dropfirst(sequence)
if n > m then
newstack = append(stack, {deleted, m, prefix})
else
newstack = stack
end
local newprefix = append(prefix, sequence[1])
newargs = {deleted, m - 1, newprefix, newstack}
end
return combinations(table.unpack(newargs)) -- tail call
end
It uses the following auxiliary functions:
function append (sequence, item)
local copy = {table.unpack(sequence)}
copy[#copy + 1] = item
return copy
end
function dropfirst (sequence)
return {table.unpack(sequence, 2, #sequence)}
end
function droplast (sequence)
return {table.unpack(sequence, 1, #sequence - 1)}
end
Example:
> combinations({1, 2, 3, 4, 5}, 3)
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
Ironically, this version achieves tail-recursion by implementing its own stack, so I am not sure it is ultimately any better than the non-tail-recursive version... Then again, I guess the function's stack actually lives in the heap (right?), because Lua's tables are passed around by reference (right?), so maybe this is an improvement, after all. (Please correct me if I'm wrong!)

Count frequency of elements into an array in Lua

I have a table in Lua:
p = {'sachin', 'sachin', 'dravid', 'Dhoni', 'yuvraj', 'kohli'}
I want to count frequency of each name in table .
test1 = {sachin=2, dravid=1, Dhoni=1, yuvraj=1, kohli=1}
I tried this program with lot of for loops .Please see my code
> function exec(ele,p)
count = 0
for k,v in pairs(p) do
if ele == p[k] then
count = count +1
end
end
return count
end
> new_table = {}
> for k,v in pairs(p) do
new_table[v] = exec(v,p)
end
>
> for k,v in pairs(new_table) do
print(k,v)
end
dhone 1
yuvraj 1
kohli 1
sachin 2
dravid 1
I want to do this more efficient way. How can I achieve this?
You can count the frequency like this:
function tally(t)
local freq = {}
for _, v in ipairs(t) do
freq[v] = (freq[v] or 0) + 1
end
return freq
end
And here's another demo example.
Using metatable may be a little unnecessary for this simple case, just showing another option:
local mt = {__index = function() return 0 end}
local newtable = {}
setmetatable(newtable, mt)
for _, v in pairs(p) do
newtable[v] = newtable[v] + 1
end
The metamethod __index above gives the table 0 as the default value.

Resources