Alternatives to table.remove()?

Hi
I need to remove a table looking like this:

{ { <int>, <int> }, <model>, <int> }

from another table. I tried using table.remove() but that doesn’t remove the table sometimes, earlier I used table[i] = nil which worked perfectly but now it sometimes sets the table as void.

Is there any alternatives or better ways of doing it?
Or some way to fix my issues?

Try to search for it with table.find, I usually do this when dealing with arrays.
Since table.find searches for the value rather than the index.

table.remove(Table, table.find(Table, ToRemove))
3 Likes

Thanks for replying, I found out the problem is that you can’t (or it’s bad to) remove things from a table while iterating through it. Although I can’t seem to come up with a fix for it.

What does your code look like?

-- Unload unused chunks --
	for i, chunkInfo in ipairs(loadedChunks) do
		if not isInTable(chunksToRender, chunkInfo) then
			local chunk = getChunkFromPos(chunkInfo[1])
			
			if chunk then
				chunk:Destroy()
				table.remove(loadedChunks, i)
			end
		end
	end

isInTable() just checks if a table is in a table.

When it comes to models and objects/instances in general, I believe once the model is destroyed, its reference will be too, so it should already be nil in the table by the time you call table.remove(loadedChunks, i).

Sorry for not mentioning that, but the chunk variables is a cloned model while chunkInfo is a table.
Looking like this:

 { { <int>, <int> }, <model>, <int> }

So I’m removing the model as well as removing info about it from the loadedChunks table.

You can also remove an item from table by doing

tableVar[index] = nil

Example:

local tab = {"hi","bye","john doe","roblox"}
tab[1] = nil -- Removes "hi"
for i,v in pairs(tab) do
 print(v) -- Prints "bye, john doe, roblox"
end

Although table.remove() and table[index] = nil acts different.

table.remove()
Removes the items with its index.
example:

local tabl = {"hello roblox!","bye roblox!"}
table.remove(tabl,1)
for i,v in pairs(tabl) do
    print(i.." = "..v) -- Prints "1 = bye roblox!"
end

Now about table[index] = nil
It wont removes the item with the index.
(Note: nil is the void so it gives the index the value of void)

Example:

local tabl = {"hello roblox!","bye roblox!"}
tabl[1] = nil
print(tabl) -- Prints 
--[[ 
{
   [1] = void,
   [2] = "bye roblox!"
}
]]--

for i,v in pairs(tabl) do
    print(i.." = "..v) -- Prints "2 = bye roblox!" As you can see it wont change the index.
end

Thats the 2 ways you can do.
I dont think theres anymore way.

1 Like

Thanks for a detailed reply, how would I ignore void values?
This is the part of the script I’m having problems with:

local function loadChunks()
	
	-- get current chunk --
	local chunkTablePos, chunkBiome = getCurrentChunk()
	local chunksToRender = getChunksInfo(getChunksInRange(chunkTablePos))
	
	--[[
	chunkInfo = {
		[1] = {x, z}
		[2] = chunk
		[3] = chunkOrientation
	}
	]]
	
	-- Unload unused chunks --
	for i, chunkInfo in ipairs(loadedChunks) do
		if not isInTable(chunksToRender, chunkInfo) then
			local chunk = getChunkFromPos(chunkInfo[1])
			
			if chunk then
				chunk:Destroy()
				loadedChunks[i] = nil
			end
		end
	end

	-- Render chunks --
	for i, chunkInfo in ipairs(chunksToRender) do
		if not isInTable(loadedChunks, chunkInfo) then
			createChunk(chunkInfo)
			table.insert(loadedChunks, chunkInfo)
		end
	end
	
end

Sometimes some chunks stay and are not destroyed. And when I print loadedChunks it shows a bunch of values as void.

It is a lot safer to use table.remove(Table, table.find('String')), since it searches for the value, rather than the index. It is not guaranteed that the order will be the same when accessing it at a later time, just because it shows that in the studio, especially for strings.

You can only sort a table with numeric indexes.

1 Like

can you print the loadedChunks and show me screen shot of the output?

I tried using that and I’m still getting one extra chunk loaded:

Then you’re probably doing something wrong in your loop, as what I provided works fine for me, and works fine in general.

Using table.remove(loadedChunks, table.find(loadedChunks, chunkInfo)) prints this:
image
(It’s always meant to be 9 chunks loaded not 10 or more)

Using loadedChunks[i] = nil prints this:
image
And leaves 3 chunks making it 12 loaded instead of 9

It is recommended not to remove the elements of an array while it is iterated, because the length of the array changes, changing the order of the remaining elements. That is why it seems that some elements are not removed or the wrong ones are removed.

A possible solution is to iterate inversely, in this way, even if we remove some elements, the remaining ones, which are at the beginning, do not suffer changes.

for i = #loadedChunks, 1, -1 do
	local chunkInfo = loadedChunks[i]
	if not isInTable(chunksToRender, chunkInfo) then
		local chunk = getChunkFromPos(chunkInfo[1])
		if chunk then
			chunk:Destroy()
			table.remove(loadedChunks, i)
		end
	end
end
2 Likes

Yes, it does change the order, which I forgot to look over.
What would be better is to save the name of the chunk to another array (or something that is unique for every chunk), then loop over the original array, and remove the ones that’s in the temporary array.

As what you’re doing right now is not really the safest option, but an example of how it could be done if you’re not futureproofing your code.

1 Like

could mention in which ways it is not safe (in which ways it could fail). That would be quite helpful to me and the community.

2 Likes

There is no guarantee that you can know its position in the table - hence it will just ignore it, looping from end to start serves no purpose because of that.

1 Like