Problem with indexs of table

Hello!
Function:

function table:rebuild()
	if type(self) == "table" then
		local Rebuilded = {}
		for i=1, #self do
			if self[i] then
				Rebuilded[#Rebuilded+1] = self[i]
			else
				print(i,"--")
			end
		end
		print(#Rebuilded, "#objs")
		return Rebuilded
	else
		error("Cant rebuild table")
	end
end

Video:

Question: Why is the function not working correctly? Why doesn’t it write “num --”(print(i,"–") in the code) after each deletion of an object?

PS:
Function where I am using table:rebuild()

	function SpriteImgs:UpdatePositionOfSpells()
		if ((#self["metadata"]["stats"]["spells"]["list"]) == 0) then do return end end
		local IsHero = false
		if self.metadata["character"]["prefix"] == "hero" then 
			IsHero = true
		end
		self.metadata["stats"]["spells"]["list"] = table.rebuild(self.metadata["stats"]["spells"]["list"])
		local TableOfSpells = self.metadata["stats"]["spells"]["list"]
		local GetX
		local GetY = - 25
		if IsHero then
			GetX = - (self.width*0.30)
		else
			GetX = (self.width*0.30)
		end
		for i=1, #TableOfSpells do
			local GetObj = TableOfSpells[i]["img"]
			GetObj.x = GetX - (i*(GetObj.width*1.15))
			GetObj.y = GetY
		end
	end

I don’t really understand what you are trying to do and why?

A few notes on your code from what I can see though:

Try print(i .. "--"), instead of print(i, "--")

You can make the code easier to read by indexing with the dot notation instead of strings when the indexes you are looking for are static values.

For example:

self.metadata.stats.spells.list

Is the same as this:

self["metadata"]["stats"]["spells"]["list"]

The naming of your variables is a little strange to me, and that also makes the code harder to read and understand. Why do you name variables GetX, GetY and GetObj instead of just x, y and obj? Something that is named with a ‘get’ prefix is by convention a function, but in your case they seem to be just simple value variables.

Let me give you another example:

function table:rebuild()
	if type(self) == "table" then
		local Rebuilded = {}
		print(#self, "#Old amount of objs in the table")
		for i=1, #self do
			if self[i] then
				Rebuilded[#Rebuilded+1] = self[i]
			else
				print("Index "..i.. " is nil.")
			end
		end
		print(#Rebuilded, "#Now amount of objs in the table")
		return Rebuilded
	else
		error("Cant rebuild table")
	end
end

local Table = {}

local function AddRect()
	local NewObj = display.newRect(50,50,25,25)
	NewObj.anchorX = 0
	NewObj.x = ((#Table)*30)
	Table[#Table+1] = NewObj
end

for i=1, 10 do
	AddRect()
end


local BtnToRemoveObj = display.newRect(50,100,25,25)
BtnToRemoveObj:setFillColor(1,0,0)
BtnToRemoveObj:addEventListener("tap", function() 
	if #Table == 0 then do return end end
	local GetRandomIndex = math.random(1, #Table)
	display.remove(Table[GetRandomIndex])
	Table[GetRandomIndex] = nil
	print("------------")
	print("GetRandomIndex is " .. GetRandomIndex)
	-- Now rebuild table to avoid Table[GetRandomIndex] as nil and get the table without index "nil"
	Table = table.rebuild(Table)
end)

Logically, all objects should be removed. But for some reason, some object will still remain, even though #Table will be equal to 0…
Try to execute this code 3 times and you will get completely different results. :smiley:


For example, then there may be one square, then two squares, although #Table == 0
Or the code can be executed correctly and then all white squares are removed…

I can’t spot the error you’re describing.

But do you know that you can use table.remove(aTable, index) instead of rebuilding your entire table to get rid of nil values?

1 Like

The length operator applied on a table returns a border in that table. A border in a table t is any natural number that satisfies the following condition:

 (border == 0 or t[border] ~= nil) and t[border + 1] == nil

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.

(I’m just quoting the manual, by the way :slight_smile: )
https://www.lua.org/manual/5.4/manual.html#3.4.7

In other words you cannot count on table being empty even when #Table is 0.

I think your experience with tables will improve immensely if you iterate over them with either
pairs or ipairs.

You can also find a lot of tips and tricks with tables on lua-users wiki, starting with tables tutorial

1 Like

@Markus_Ranner Thank! I knew about the table.remove(), but did not know that it can also “rebuild” the table… Your advice helped me, but it’s a pity that my code didn’t work as it should
@jedihenryk Thanks, I read more articles on tables. Anyway, I’m glad that my experience with code has become much better than it was at the very beginning of my arrival on the forum :slightly_smiling_face:

1 Like

you cannot iterate over table as array, read more about tables.
table is mainly a dictionary DS, it’s not array that mean not all members stored consequentially (by index)
and #table doesn’t return number of valid entries in table,

to iterate over table entries use:
for k,v in pairs(table_name) do

instead of
for i,v in ipairs(table_name) do
or iterate by index

anyway why you need to rebuild table?

There are two basic ways to index objects in table, which affect the way you iterate over the table.

(Note: I am not talking about table functions like insert, etc here. I am talking about the indexing method you use.)

  1. Numeric Indexes:
local some_objects = {}

for i = 1, 10 do
   local obj = display.newCircle( ... )
   some_objects[#some_objects+1] = obj  -- LOOK HERE
end

Now, you can iterate over the table using numbers:

for j = 1, #some_objects do
   print( some_objects[j].x, some_objects[j].y )end
end

(You can also use ipairs() and pairs() iteration techniques.)

  1. Object indexes:
local some_objects = {}

for i = 1, 10 do
   local obj = display.newCircle( ... )
   some_objects[obj] = obj -- LOOK HERE
end

Now, you can iterate over the table using pairs():

for k,v in pairs(some_objects) do
   print( v.x, v.y )
end

You CANNOT use number iteration (including ipairs()) on this table.

print( #some_objects) -- prints 0
  1. You can simultaneously use numeric indexing and have key-value pairs if you like, but that is generally a messy proposition.
local some_objects = {}

for i = 1, 10 do
   local obj = display.newCircle( ... )
   some_objects[#some_objects+1] = obj -- LOOK HERE
end

some_objects.purpose = "game objects"

Now, some_objects has 10 numerically indexed objects in it and a field ‘purpose’ with the value ‘game objects’ in it.

Gotcha: If you do what I just did in 3 and attempt to JSON encode a table with both numeric entries and key-value pairs, then decode the JSON, all numeric indexes will be strings and not indexeable by numeric iterator.