Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Why is the Instance Sort not being removed in this table?

I'm trying to remove 3 Instances from this table, the Script and two parts named Base and Sort individually, however in the first loop, the Instance Sort is ignored, for whatever reason. But in the second loop, the Instance Sort is included. I'm really confused. I thought that maybe the game didn't fully load yet, and that Sort wasn't loaded, so i added this repeat loop to make sure that there are only 13 instances in the table (the number of children), but it still didn't work. Every child's name is printed except for Sort.

Server script:

local parts

repeat
	parts = script.Parent:GetChildren()
until #parts == 13

for i, child in pairs(parts) do
	print(child.Name)
	
	if child == script or child.Name == 'Sort' or child.Name == 'Base' then
		table.remove(parts, i)
	end
end

for i, child in pairs(parts) do
	child.SurfaceGui.TextLabel.Text = child.Name
end

I also get an error that states that Sort doesn't have a child named SurfaceGui, because, well, it doesn't, but Sort shouldn't be in the table at all.

1 comment

0

I edited my answer, I hope this explains it better.

1 answer

✓ Accepted answer

First and foremost you should use ipairs instead of pairs for arrays, as pairs is not guaranteed to iterate in order. However that is not what is causing an issue here.

Problem is with table.remove. What it is doing its removing an element from the table and moves all elements to the "right" of this part, one space "left". (Left and right is just imaginary, as you were to write all elements on paper)

So when you iterate through your table, you remove element called Base or the script. Elements are moved, and Sort is being moved into that spot. Since next iteration checks the next element on the paper, Sort slips under the radar.

To solve this, you should use a dictionary or remove just one element at a time. Other option is to replace an element with false, and check it in the next loop. On the other hand, If you put nil as a value, your array will become a dictionary. This will solve your issue as well.

for i, child in pairs(parts) do
    print(child.Name)

    if child == script or child.Name == 'Sort' or child.Name == 'Base' then
        parts[i] = nil --by doing this your array will become a dictionary, and you cannot use #parts to count elements anymore.
    end
end

for i, child in pairs(parts) do
    child.SurfaceGui.TextLabel.Text = child.Name
end

Have a nice scripting session.

Edit - visual representation (just an example)

--[[
Array 	[1]		[2]		[3]		[4]		[5]		[6] 
		Part 	Base 	Sort	Part 	Part 	script

table.remove METHOD
1. Loop checks 1st element - no action
2. Loop checks 2nd element - Base gets removed, elements to the right are moved
Array 	[1]		[2]		[3]		[4]		[5]		 
		Part 	Sort		Part	Part script
3. Loop checks 3rd element - notice how `Sort` is now at 2nd position, therefore it is not checked.

nil METHOD
1. Loop checks 1st element - no action
2. Loop checks 2nd element - index gets removed, elements ARE NOT moved
Array 	[1]		[nil]		[3]		[4]		[5]		[6] 
		Part    [removed]	Sort	Part		Part 	script
Since index [2] is now missing, array becomes a dictionary. Elements are now not in proper order (2 is gone), #parts cannot be used. 
3. Loop checks 3rd element - `Sort` found!
--]]

I hope this explains it better. To preserve an array you would need to put something at index no 2. Distinction between arrays and dictionaries is subtle, and to lua everything is a dicionary. Think of it this way : A table is an array ONLY when all its elements are indexed with numbers from 1, without any numbers missing.

2 comments

0

I'm not entirely sure I understand. Yes, it works, I'll give you that, but why does using a dictionary fix it? How does parts[i] = nil change the array into a dictionary?

0

Answer edited.

This discussion is preserved as it was. New answers, comments, and votes are closed.