My script does not work as intended

So, I am developing a community resource (that will soon be available) called: “BT (better table)”

In the process I encountered a “bug” in the code that do not want to work as intended, it will deleate an index but set to “nil” another, I need help, please, and thanks for everyone.

Remove code:

tbl.remove = function(Arguments: any, tableInst)
		if tableInst == nil then tableInst = tbl end

		if tableInst[0] then
			task.spawn(function()
				for i,v in pairs(tableInst[0]) do
					if type(v) == "table" then
						--It's a table

						for j,k in pairs(v) do
							if type(Arguments) == "table" then
								for l,m in pairs(Arguments) do
									if tostring(m) == tostring(k) then
										print("have to remove here")
									end
								end
							else
								if tostring(k) == tostring(Arguments) then
									print("have to remove here")
								end
							end
						end
					else
						--It's not a table

						if type(Arguments) == "table" then
							for j,k in pairs(Arguments) do
								if tostring(k) == tostring(v) then
									tableInst[0][i] = nil --This does "deleate" an index but not the numeric one
								end
							end
							
							
						else
							if tostring(v) == tostring(Arguments) then
								print("have to remove here.")
							end
						end
					end
				end
			end)
		end
	end

Run code:

local bt = BT.new()

bt.add({"hey", "how's going?", 12041, Vector3.one})

bt.remove({"hey", 12041})

print(bt)

Output:

Screenshot 2024-04-11 alle 15.23.53

Anyone know’s how to solve this? If so please write it down below! Thanks all

Lua tables are a rather eccentric datastructure, and their nuances provide many pitfalls for programmers coming from other languages, two of which you are encountering here:

  1. Lua tables consist of two separate datastructures: and array with natural number indices, and a dictionary (unordered key, value map) where the keys can be both value types (e.g. strings and numbers) or reference types (e.g. Player, Part, or Model instance references).
  2. The array part is 1-indexed.

The ipairs function will only iterate through the array part of the table, and your table will only have an array part if it has non-nil values associated with consecutive natural number indices starting at 1. If you don’t have a value for key 1, you don’t have an array. If you have non-nil values stored for indices 1, 2, 3, 4, 6, 7, 8, 9, etc… the array part will only be for indices 1 through 4, the lack of an element stored at index 5 means that indices 6, 7, 8, 9… are dictionary keys in the unordered map part of the table, unreachable with ipairs.

The pairs function will iterate through all keys in the table, both the array indices and the dictionary keys. However, iteration through the dictionary keys can be in any order. So in my above example, using pairs on that table with key 5 missing, you might see it iterated in the order 1, 2, 3, 4, 9, 6, 8, 7… obviously this is a huge pitfall for someone used to other languages where arrays and maps are separate beasts, not combined under the hood like in a Lua table!

In your code, you are using 0 as a key, which right off the bat means you’ve made an unordered dictionary. The line tableInst[0][i] = nil can also take a nice array, and split it into an array part and dictionary, because it breaks the consecutive index rule, adding a gap where index i is no longer a key in the table.

4 Likes

Completely unrelated, but, that was probably the best someone has ever explained that, bless you for that!

I do know, here’s why I am making a community resource with a java datastructure.

I do perfectly know Lua nd Luau. I do know that the 0 index is not included in the ipairs, because for the Luau system it’s not an array integer.

My real question is why it does set to nil a value and removes it and does not for the other.

Thanks for the explanation tho.

Ah, gotcha. I think we’d need to also see your add() function to know for sure. Have you tried doing print(bt) before bt.remove()? I’m wondering if possibly the remove is fine, and it’s the add where things are going wrong and not adding the first element.

from what I know, in a sequence (an array-like table where keys are consecutive integers), Lua and Luau expect indices to be consecutive. If you simply set an index to nil , you break the sequence making a sparse array. and your sequence is messed up, i think.

so, stick to .remove(), or you would need to re-index / shift all elements over

Okay, I will not share all the code because it’s 590 lines roughly
Here’s the code:

tbl.add = function(Arguments: any, toSubTable: boolean?, subTable: number?, tableInst)
		if tableInst == nil then tableInst = tbl end

		if type(Arguments) == "table" then
			local Indexes 
			local sentMsg = false

			for i,v in pairs(Arguments) do
				Indexes = tbl.findAndReturnFoundTimes(v, i, Arguments)

				if Indexes[1] == 1 then continue end

				Arguments[Indexes[2]] = nil

				if sentMsg == false then
					warn("A duplicate has been found into your adds, it got removed, but the table's indexes may not be as you though.")
					sentMsg = true
				end

				if tonumber(Indexes[2]) == 0 then
					for j,k in pairs(Indexes) do
						Indexes[j] = nil
						Indexes[j-1] = k
					end
				else
					for j,k in pairs(Indexes) do
						if (j-1) > 0 then
							Indexes[j] = nil
							Indexes[j-1] = k
						end
					end
				end
			end
		end

		if toSubTable == true then
			if not tableInst[0] then
				tableInst[0] = {}
				return warn("Table did not had any subtables at that moment, remember to add the 0 key else this will not work.")
			else
				if tableInst.find(subTable) == true then
					subTable = tableInst.findAndReturn(subTable)

					if not tableInst[subTable[1]][0] then
						tableInst[subTable[1]][0] = {}

						if type(Arguments) == "table" then
							for i,v in pairs(Arguments) do
								if type(i) ~= "number" then return end

								tableInst[subTable[1]][0][i] = v
							end
						end

					else
						tableInst[subTable[1]][#subTable[2]+1] = {}

						if type(Arguments) == "table" then
							for i,v in pairs(Arguments) do
								if type(i) ~= "number" then return end

								tableInst[subTable[1]][#subTable[2]][i-1] = v
							end
						else
							tableInst[subTable[1]][#subTable[2]] = Arguments
						end
					end
				end
			end
		else
			if not tableInst[0] then
				tableInst[0] = {}

				if type(Arguments) == "table" then
					local lastIndex

					for i,v in pairs(Arguments) do
						if type(i) ~= "number" then return end

						if not tableInst[0][0] then
							tableInst[0][0] = v
							lastIndex = 0
							continue
						end

						tableInst[0][lastIndex+1] = v

						lastIndex += 1
					end
				else
					tableInst[0] = Arguments
				end
			else
				tableInst[#tableInst+1] = {}

				if type(Arguments) == "table" then
					local lastIndex

					for i,v in pairs(Arguments) do
						if type(i) ~= "number" then return end

						if not tableInst[#tableInst][0] then
							tableInst[#tableInst][0] = v
							lastIndex = 0
							continue
						end

						tableInst[#tableInst][lastIndex+1] = v
						print(tableInst[#tableInst][lastIndex+1])

						lastIndex += 1
					end
				else
					tableInst[#tableInst] = Arguments
				end
			end
		end

		return tableInst
	end

Re-indexing was my last choice in the book, but I think I will have to use it…

sadly :frowning: seems like the only approach