Lua deleting an item from table (CoronaSDK) - lua

Been trying to work this out for hours and not getting anywhere despite lots of searching, so if somebody can help that would be great
My issue is I have a table of objects which are added like this
enemies[enemy_id] = enemy
Now when there is a collision at the end of the map I want to remove that enemy from the table. I have tried removing by
enemies[enemy_id] = nil
But when it gets to the last enemy the table is already empty for some reason. Say there's 3 enemies in a table, I print the count of the table. The first one is removed it shows 2 left, 2nd is removed it shows 0 left. Doesn't make sense
So how do you remove an item from a table? I have also tried table.remove but I need to key the same keys because they are the id of the enemy. I can post an example if need be

When working with "sparse keys" in Lua tables this pattern usually pays off for me:
-- add item to registry
registry[object] = key
registry[key] = object
-- iterate over all items in registry
for k,v in pairs(registry) do
if type(k) == "number" then do_something(k,v) end
end
-- remove item with key K from registry:
registry[registry[K]] = nil
registry[K] = nil
-- remove item O from registry:
registry[registry[O]] = nil
registry[O] = nil

Since # won't work on sparse arrays, as other suggested, and my solution would be to use 0 index (or simply another variable) as count:
enemies[0] = 0
Then, when you add an enemy, increase the counter, when you remove one, decrease it. Simple as that.

Related

Add a name to an array, check array to see if name exists, run code

Brand new to lua as of a few hours ago, I have some moderate background in C++ and Java but nothing amazing.
I'm trying to work on an addon for a game that checks for players around me, and if so(within 10 yards) greets them.
It works great, except I ONLY want it to run once per player, as it would be spammy and annoying to constantly greet people.
I figured the best way to do this was to store their character name in an array, but I'm struggling to understand the syntax of arrays.
function Wave()
local totalObjects = GetObjectCount()
local shouldMessage = false
local player = GetActivePlayer()
arrayNames = {}
for i = 1, totalObjects do
local object = GetObjectWithIndex(i)
if object ~= player and UnitIsPlayer(object) == true and UnitIsDead(object) == false then
local yards = GetDistanceBetweenObjects(player, object)
local name = ObjectName(object)
----------------- The beginning of my issue ----------------
if yards < 10 and arrayNames[i] ~= name then -- if name isnt in array already?
arrayNames[i] = name -- trying to add the name to array
print(arrayNames[i])
break
end
end
end
if storeName then
end
end
The issue is that your table is getting cleared after each call to Wave. This is because you are doing arrayNames = {} inside your function, so each time it is run the table is set to a new empty table. you can define arrayNames outside of your Wave function or change it to arrayNames = arrayNames or {} The second option will set arrayNames equal to arrayNames when it is defined or to a new table if it is not defined.
Additionally
Your code only checks if the name exists in the array at the specific index, rather then checking the whole array. If the player's index can change then you will likely greet them again using this method.
You will need to go over the whole array too be sure you have not greeted this person already. This means as you greet more and more people the check will get longer and longer
Rather than use an array, I suggest using a set:
if yards < 10 and not arrayNames[name] then -- if name isnt in set already?
arrayNames[name] = true -- trying to add the name to set
print(name)
break
end
simply add to the table using the name as the key and setting the value to true this will provide O(1) performance for your check.
Here is more information on sets:
https://en.wikipedia.org/wiki/Set_(abstract_data_type)
In computer science, a set is an abstract data type that can store unique values, without any particular order. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set.

Potential problems with storing the second table of two dimensional arrays in the index

In the past I found myself using a table as index and value of
a table when the order was irrelevant.
Since every table returns a unique value they are save to use as
index and with that I already got all the information I want to
use later on in the program. Now I did not see any similar lua code
jet and didn't use it in a non test-program. So I'm worrying that I
might get some unforeseen/unexpected problems when using this method.
example:
a = {1,2,3,4,5} --some testing values
b = {2,nil,4,nil,1}
c = {3,nil,nil,nil,2}
d = {4,nil,1,nil,3}
e = {5,1,2,3,4}
tab = {a,b,c,d,e}
t = {}
for i, v in pairs(tab) do
t[v] = 0
end
for iv in pairs(t) do --is almost every time outputting it in a different order
print(iv[1],iv[2],iv[3],iv[4],iv[5]) --could be a list of data where you have to go through all of it anyway
end
io.read()
Now I can store some additional information in t[v] but if I don't have
any is there maybe some lua-type that is smaller?
Edit:
Does this go well with the use of weak-tables?
Note:
Standard 2d table: table[key1] = table
table[key1][key2] <-- contains stuff
this version: table[table] = anything but nil <-- not accessible over table[key1][key2]
key1[key2] <-- contains stuff
It's fine to use a table as a key in another table.
However, note that different tables will be different keys, even of the tables have the same contents.

remove all entries with specified value in table

I want to delete all entries from a table, wich equals a given value.
Now, I got a pretty little problem one might to know, how to handle.
This is the Code:
function(list_to_search_in, compared_value, invert)
for k,v in pairs(list_to_search_in) do
if invert and v ~= compared_value then
table.remove(list_to_search_in, v)
if not invert and v == compared_value then
table.remove(list_to_search_in, v)
end
end
end
The Problem:
Let's say the table is { 1, 2, 3, 2 }. So when I'm iterating through that loop and come to the first match, it's removed from the table. This means the value and the key is deleted.
Now the key of the deleten value is assigned to the next value in line. But due the skript will check the value of the next key, this value (whichs kay has been just altered) will never be checked.
I thought, a simple
k = k - 1
after a remove would do the job, but it doesn't.
v = nil
would do great I think, but only if garbage-collector does not do his job in this very moment the pairs iterates to the next value.
Anyone has an idea? I would prefer an text-based hint to a finished syntax which solves the problem.
Don't use table.remove for this. It squeezes the "hole" out of array-like tables. That's not allowed during an iteration using pairs/next. Just set the value to nil.
If you need to squeeze holes out of the table then you can either create a new table and populate it with only the values you want to keep or do the removals during the first pass and then squeeze out holes in a second pass.
Also the order of item traversal when using pairs is not guaranteed in any way.

Lua table continues to be empty, even though I am giving it stuff

In my Lua-powered game, I am trying to create an Explorer to see all the instances that have been created. I've created a function inside my DataModel "class" (as I like to call it) that will scan the children of an item, and put it neatly inside a table.
function DataModel.ObjectToTable(obj)
children = {}
for i,v in pairs(obj:GetChildren()) do
table.insert(children, DataModel.ObjectToTable(v))
end
print(obj.Name)
dmyself = {}
dmyself.Name = obj.Name
dmyself.Object = obj
dmyself.Children = children
print(#dmyself)
return dmyself
end
The issue is that, the print(#dmyself) is coming out as 0. But as you can see, I just set 3 things inside of it. What could cause such a thing to happen? Am I doing something obviously wrong?
The print(obj.Name) line is returning what it should. I am simply stuck on 'dmyself'.
# is the length of the array part of the Lua table; it only takes integer keys into account. More specifically,
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 you use pairs, you can see that your table is not empty. But since there's nothing in the array part of the table, it's length is zero.

Corona SDK (LUA) - Trouble With Inserting Into Table

I have searched around quite a bit and couldn't quite find a solution for this. Any help you can offer would be appreciated.
-- The array compiled of enemies only allowed in the current
-- level phase
local EnemyList = {}
-- Counter to determine the next spot in the EnemyList
-- array to insert into
local counter = 1
for i=1,#Enemies do
if Enemies[i].phase == 0 or Enemies[i].phase == which_phase then
EnemyList[counter].src = Enemies[i].src
EnemyList[counter].exp = Enemies[i].exp
counter = counter + 1
end
end
I am getting an error about attempting to index a nil value, in reference to the EnemyList table/array. What I am trying to accomplish is I am trying to compile a new array of only enemies that are allowed. I guess I am unsure how to insert a new row into the EnemyList table. I tried using table.insert, but the value parameter is required, and I am not sure how to do that with the fact that I am storing multiple values into the EnemyList array.
Any help or insight on the proper way to insert a new row into an empty table/array would be much appreciated. Thanks!
EDIT:
I got a working solution, but I figured I should update the code here if anyone in the future finds it.
-- The array compiled of enemies only allowed in the current
-- level phase
local EnemyList = {}
for i=1,#Enemies do
if Enemies[i].phase == 0 or Enemies[i].phase == which_phase then
table.insert( EnemyList, { src = Enemies[i].src, exp = Enemies[i].exp } )
end
end
You can store tables within tables in Lua. Tables are indexed in one of two ways: First, by index number. This is what table.insert uses; it will add an entry at the next index number.
The second way is by key; e.g.
> t = {}
> t.test = {}
> =t.test
table: 0077D320
You can insert tables into tables; this is how you create a 2D table. Because of the way you've defined your tables, type(EnemyList[counter]) = table.
You can insert new entries into tables by running table.insert(table, value). This will assign value to the next available numeric entry. type(value) can also be a table; this is how you create "multidimensional arrays" in Lua.
As an aside, instead of using for i=1,#Enemies I would suggest using for i,v in ipairs(Enemies). The second one will iterate over all numerical entries in the Enemies table.

Resources