How do I keep an array's order when something is taken out?

so, i’m trying to write a custom inventory script. if an item is removed, i want the other items in front in the inventory to slide smoothly into place without massive reorganizing.

for example, let’s say that there are 4 items in my inventory and they’re put into an array. item 1 is a cup, 2 is a plate, 3 is a pencil and 4 is a notepad. if 2 gets removed, i want everything after 2 to keep its order but not get reshuffled. like…

[cup] [plate] [pencil] [notepad] → [cup] [pencil] [notepad], NOT [cup] [notepad] [pencil] OR [cup] [nothing] [pencil] [notepad]

how would i do that? right now, i used table.sort to put everything into numerical order, but i’m not sure if that’s necessary or not. what do i do here without overcomplicating the script?

local Table = {"cup", "plate", "pencil", "notepad"}

table.remove(Table, 2)

this works fine

2 Likes

this is the most obvious answer and i somehow glossed over it thank you

1 Like

actually, really quick, i tested that. i wanted to make sure it worked, so when i typed

print(Table[2])

it gave me nil instead of “pencil”. did i do something wacky

Likely, since his code should work find. Can you show us your code?

yeah, here

local tablee = {"cup", "plate", "pencil", "notepad"}
table.remove(tablee, 2)
print(table[2])

if you mean the full thing of what i’m trying to do, here it is so far (plus some screenshots from explorer for some context JUST in case)
the script i’m working in is itemhandler

image

i think the only part of the script that would be necessary though is chara.ChildRemoved:Connect’s function, but just in case here’s everything:

local itemmenu = script.Parent:WaitForChild("items")
local labelbase = itemmenu:WaitForChild("itembase")
local player = game:GetService("Players").LocalPlayer
local chara = player.Character or player.CharacterAdded:Wait() -- put in a way to listen for when the character reloads
local inv = player:WaitForChild("Backpack")
local spacing = 8 -- spacing between list of items

local function insertitem(item, storagenumb)
	item:SetAttribute("itemindex", storagenumb + 1)
	itemmenu:SetAttribute("items", storagenumb + 1)
	local h = labelbase:Clone()
	h.Name = tostring(storagenumb + 1)
	h.Position = UDim2.new(h.Position.X.Scale, h.Position.X.Offset, 0, 25 + (25*storagenumb) + (spacing*storagenumb))
	h.Text = item.Name
	h.Visible = true
	local objvalue = Instance.new("ObjectValue") -- for when the menu calls to use the item, in case there is multiple of said item
	objvalue.Name = "itemmenu_index"
	objvalue.Parent = h
	objvalue.Value = item
	h.Parent = itemmenu
end

inv.ChildAdded:Connect(function(item)
	print("item added: "..item.Name)
	local storage = itemmenu:GetAttribute("items")
	local ordervalue = item:GetAttribute("itemindex") -- if it was in the inventory previously, where was it in the menu
	if storage < 8 then
		if not ordervalue then -- it was never in the menu before, so this must be a NEW item
			insertitem(item, storage)
		else -- otherwise, this has been in the inventory before...
			local placeinmenu = itemmenu:FindFirstChild(tostring(ordervalue)) -- find where it should be in the menu
			if not placeinmenu or placeinmenu.itemmenu_index.Value ~= item then --if the place in the menu doesn't exist OR it's not the same object, treat it as a new item
				insertitem(item, storage)
			else --otherwise, it was probably taken out, so let's just make the label for it white again
				placeinmenu.TextColor3 = Color3.new(1, 1, 1)
			end
		end
	else
		--do something here later to remove the item from the backpack
	end
	
end)
inv.ChildRemoved:Connect(function(item)
	print("item removed: "..item.Name)
	--assuming this item is being used, let's gray it out (maybe make it yellow...?)
	local ordervalue = item:GetAttribute("itemindex")
	local placeinmenu = itemmenu:FindFirstChild(tostring(ordervalue))
	placeinmenu.TextColor3 = Color3.new(1, 1, 0)
end)
chara.ChildRemoved:Connect(function(item)
	if item:IsA("Tool") and item.Parent ~= inv then -- is this a tool and is it being put back into the backpack? if not...
		local storage = itemmenu:GetAttribute("items")
		local ordervalue = item:GetAttribute("itemindex") -- where the tool was in the inventory
		local placeinmenu = itemmenu:FindFirstChild(tostring(ordervalue))
		local items = {}
		for i, v in pairs(itemmenu:GetChildren()) do -- and let's get a count of what's currently in the menu!
			if tonumber(v.Name) then -- just to make sure this is storing an item and is not the use, drop or info options...
				items[v.Name] = v -- let's put it in!
			end
		end
		table.sort(items, function(a, b) -- sort by lowest to highest
			return a[2] < b[2] -- if a is smaller than b, a goes first
		end)
		placeinmenu:Destroy() -- destroy the place in the menu it was in...
		table.remove(items, ordervalue)
		for i, v in pairs(items) do --lets re-organize the menu now that we removed the old item!
			v.Name = i
			v.Position = UDim2.new(v.Position.X.Scale, v.Position.X.Offset, 0, 25 + (25*(i-1)) + (spacing*(i-1)))
		end
		itemmenu:SetAttribute("items", storage - 1)
	end
end)

Is this a direct copy? If so, you issue is printing table[2] instead of tablee[2]

oh not a direct copy, i just made a typo there. fixing the typo worked, but when i do that, the order doesn’t seem to change for the actual thing i’m doing. perhaps that’s on me though for not showing the full context first, haha. cause right now what ends up happening is

this awkward space

edit: should also note that putting in print(items[ordervalue]) in the last function of the script gives me nil, which is why i’m having this issue

That is because you might have forgot to remove the TextLabel listed there.

placeinmenu:Destroy() -- destroy the place in the menu it was in...

this line here destroys the old textlabel though? unless i’m missing something else

ok just figured out the issue. it was because in table.sort i used a[2] < b[2] instead of tonumber(a.Name) < tonumber(b.Name), along with items[v.Name] = v instead of items[tonumber(v.Name)] = v. that was it that was literally it

1 Like