Changing orders of Tables?

Hi, with the help of @Elttob I was able to re-work a version of a custom Backpack Gui I’m working on to allow items to move backwards if one were removed. I’m now looking to reverse this so that if a specific item [E.G. Named: “Wand”] is added into the Backpack then it is placed in [1] and is the first item in the order and all others, if there are any, are moved up to the next corresponding one.

Now, I’ve tried reversing what I’ve learned with the removing; but that doesn’t seem to work. I am relatively new to the use of Tables and was wondering if anyone could please help?

Table
local inputKeys =
	{["One"] = {Text = "1"};
	 ["Two"] = {Text = "2"};
	 ["Three"] = {Text = "3"};
	 ["Four"] = {Text = "4"};
	 ["Five"] = {Text = "5"}}

local inputOrder =
{inputKeys["One"]; inputKeys["Two"]; inputKeys["Three"]; inputKeys["Four"]; inputKeys["Five"]}
ChildAdded
function ChildAdded(Child)
	if Child:IsA("Tool") then
		local isNew = true
		for _, Value in pairs(inputKeys) do
			local Tool = Value["Tool"]
			if Tool then
				if Tool == Child then
					isNew = false
				end
			end
		end
		if isNew == true then
			for i = 1, #inputOrder do wait()
				local Tool = inputOrder[i]["Tool"]
					if inputOrder[i]["Tool"] == Child then
						inputOrder[i]["Tool"] = nil
					end
				if not Tool then
					inputOrder[i]["Tool"] = Child
					break
				end
			end
		end
		Configure()
	end
end
ChildRemoved
function ChildRemoved(Child)
	if Child:IsA("Tool") then
		if Child.Parent ~= Player.Character and Child.Parent ~= Player["Backpack"] then
			for i = 1, #inputOrder do wait()
				if inputOrder[i]["Tool"] == Child then
					inputOrder[i]["Tool"] = nil
					break
				end
			end
			for index=1, #inputOrder - 1 do
				wait()
			    local thisItem = inputOrder[index]
			    local nextItem = inputOrder[index + 1]
			    if thisItem["Tool"] == nil and nextItem["Tool"] ~= nil then
			        thisItem["Tool"] = nextItem["Tool"]
			        nextItem["Tool"] = nil
			    end
			end
		end
		Configure()
	end
end
1 Like

Try reading the dev hub article on tables. Tables | Documentation - Roblox Creator Hub

1 Like

Thank you - I have read through this before, at length, and again recently - I’m still struggling with the situation. :slight_smile:

Now I’m not that familiar with tables, but what I would do is to rewrite the entire table. But that’s just me, I’m sure there is an easier way to do it.

1 Like

When adding an item at index n, loop for i = #table, -1, n do, and move table[i] to table[i + 1]. Then you can put the item in at index n.

Edit: Sample code for clarification

local list = {1, 2, 3, 5, 6}

local function addItem(item, index)
	-- move everything behind index back
	for i = #list, -1, index do
		list[i + 1] = list[i]
	end
	-- place item in
	list[index] = item
end

addItem(7, 4)

for i = 1, #list do
	print(list[i])
end
-- Output >> 1 2 3 7 5 6
2 Likes

cc @KossmoZ
Just saying, it would most likely be easier to use table.insert(table, index, value). The above is pretty much what the function does behind the scenes, but it’s easier to use.

--Sample code
local list = {1, 2, 3, 5, 6}
table.insert(list, 4, 4)

--Same ouput: 1, 2, 3, 4, 5, 6

And a reference article:
table.insert

3 Likes

Wow I completely forgot about that. I was doing it manually, but this way is definitely much more efficient.

3 Likes

Hi, I’m trying to wrap my head around these tables - As your list only lists 1 - 6 with no 4; table.insert would added a fourth variable but what if one were to already exist and just needs moving forward one space? :L

@MayorGnarwhal

Think of it like this:

local tableSample = {index 1, index 2, index 3...}

table.insert shoves everything over, then replaces the specified index with the specified value.

local sample = {3, 9, 2}
--`3` is at index 1, `9` is at index 2, `2` is at index 2
table.insert(sample, 2, 10) --Table, index, value
--So, the above turns the table into {3, index 2, 9, 2}
--Then: {3, 10, 9, 2}
1 Like
local newtable = {one,two,three}
local tablevar = newtable[1]
table.remove(newtable,1)
table.insert(newtable,2,tablevar)

--expect output: two,one,three

Again I’m no master at tables, but I think this may be a simple way to do that.

1 Like

@ThatTimothy; @MayorGnarwhal; @Eandvwigle.

So - As my tables are preset with suches as:

{inputKeys["One"]; inputKeys["Two"]; inputKeys["Three"]; inputKeys["Four"]; inputKeys["Five"]}

if I were to use Table.Insert would there not then be six variables?

Full script for reference:
local System = {}

local UserInputService = game:GetService("UserInputService")

local CoreGui = script.Parent
local Gui = CoreGui["ToolBar"]

local Player = game:GetService("Players").LocalPlayer

local StarterGui = game:GetService("StarterGui")
local success, result = pcall(StarterGui.SetCoreGuiEnabled, StarterGui, Enum.CoreGuiType.Backpack, false)

local inputKeys =
{["One"] = {Text = "1"};
 ["Two"] = {Text = "2"};
 ["Three"] = {Text = "3"};
 ["Four"] = {Text = "4"};
 ["Five"] = {Text = "5"}}

local inputOrder =
{inputKeys["One"]; inputKeys["Two"]; inputKeys["Three"]; inputKeys["Four"]; inputKeys["Five"]}

function System:Enable()
	local PlayerTools = Player["Backpack"]:GetChildren()
	for i = 1, #PlayerTools do wait()
		if PlayerTools[i]:IsA("Tool") then
			for i = 1, #inputOrder do wait()
				local Value = inputOrder[i]
				if not Value["Tool"] then
					Value["Tool"] = PlayerTools[i]
					break
				end
			end
		end
	end
	Create()
	UserInputService.InputBegan:Connect(onKeyPress)
	Player.Character.ChildAdded:Connect(ChildAdded)
	Player.Character.ChildRemoved:Connect(ChildRemoved)
	Player["Backpack"].ChildAdded:Connect(ChildAdded)
	Player["Backpack"].ChildRemoved:Connect(ChildRemoved)
end

function Create()
	for i = 1, #inputOrder do wait()
		local Value = inputOrder[i]
		local Template = script["Template"]:Clone()
		Template.Parent = Gui
		Template["TextLabel"].Text = Value["Text"]
		Template.Name = Value["Text"]
		
		local Tool = Value["Tool"]
		if Tool then
			if Tool.TextureId == "" then
				Template["ItemName"].Text = Tool.Name
			else
				Template["Item"].Image = Tool.TextureId
			end
			Template.Visible = true
		end
		
		Template["Item"].MouseButton1Down:Connect(function()
			for i, Value in pairs(inputKeys) do
				if Value["Text"] == Template.Name then
					EquipTool(Value["Tool"]) 
				end 
			end
		end)
	end
end

function onKeyPress(inputObject)
	local Key = inputObject.KeyCode.Name
	local Value = inputKeys[Key]
	if Value and UserInputService:GetFocusedTextBox() == nil then
		EquipTool(Value["Tool"])
	end 
end

function EquipTool(Tool)
	if Tool then
		if Tool.Parent ~= Player.Character then
			Player.Character:WaitForChild("Humanoid"):EquipTool(Tool)
		else
			Player.Character:WaitForChild("Humanoid"):UnequipTools()
		end
	end
end

function ChildAdded(Child)
	if Child:IsA("Tool") then
		local isNew = true
		for _, Value in pairs(inputKeys) do
			local Tool = Value["Tool"]
			if Tool then
				if Tool == Child then
					isNew = false
				end
			end
		end
		if isNew == true then
			if Child.Name == "Tool" then
				table.insert(inputOrder, 1, Child)
			else
				for i = 1, #inputOrder do wait()
					local Tool = inputOrder[i]["Tool"]
						if inputOrder[i]["Tool"] == Child then
							inputOrder[i]["Tool"] = nil
						end
					if not Tool then
						inputOrder[i]["Tool"] = Child
						break
					end
				end
			end
		end
		Configure()
	end
end

function ChildRemoved(Child)
	if Child:IsA("Tool") then
		if Child.Parent ~= Player.Character and Child.Parent ~= Player["Backpack"] then
			for i = 1, #inputOrder do wait()
				if inputOrder[i]["Tool"] == Child then
					inputOrder[i]["Tool"] = nil
					break
				end
			end
			for index=1, #inputOrder - 1 do
				wait()
			    local thisItem = inputOrder[index]
			    local nextItem = inputOrder[index + 1]
			    if thisItem["Tool"] == nil and nextItem["Tool"] ~= nil then
			        thisItem["Tool"] = nextItem["Tool"]
			        nextItem["Tool"] = nil
			    end
			end
		end
		Configure()
	end
end

function Configure()
	for _, Value in pairs (inputKeys) do
		local Tool = Value["Tool"]
		local Item = Gui:FindFirstChild(Value["Text"])
		if Tool then
			Item.Visible = true
			if Tool.TextureId == "" then
				Item["ItemName"].Text = Tool.Name
			else
				Item["Item"].Image = Tool.TextureId
			end
			if Tool.Parent == Player.Character then
				Item.ImageTransparency = .5
			else
				Item.ImageTransparency = .75
			end
		else
			Item.Visible = false
			Item["Item"].Image = ""
			Item["ItemName"].Text = ""
		end
	end
end

System:Enable()

return System

If you use table.insert, the length will always be increased by 1, as a new element is inserted at the specified index, after pushing the rest down.

What exactly do you want your code to do? What’s the before and after?

1 Like

I want it to work where if a new Child is added into the Backpack i.e. collected; and it’s titled: “Wand” then that’s always placed in Slot1 to be the front of the queue.

If any other item is in Slot1 at the time of collection, i.e. “Potion” then when “Wand” becomes Slot1; Potions becomes Slot2 and carrying on for others if found.

You can achieve this by doing:

table.insert(slots, 1, newItem)

This will bring the new item to the front.

Are you using a custom backpack / hotbar?

2 Likes

Is there a cap to how many tools can be in backpack? Your code seems to be structured that way.

If there can only be 5 tools, and the player picks up a 6th then you can do a few things;

  • Force drop the incoming tool
  • Drop the tool previously in the first slot
  • Insert the tool, and then remove the 6th index
1 Like

I am.

ToolBarGui.rbxm (9.8 KB)

@MayorGnarwhal - Oooh I didn’t actually think that far ahead! I’ll look into that.

Using table.insert() I’m met with the error:
[Tool is not a valid member of Tool] in my ChildRemoved function.

Currently this is how I’m working on moving the indexes forward by one however I am currently experiencing some unintended bugs that are causing the other segments of the table to become occupied by multiple of the same tools.

    for i = 1, #inputOrder - 1 do wait()
    	local currentIndex = inputOrder[i]
    	local nextIndex = inputOrder[i + 1]
    	if currentIndex["Tool"] ~= nil then
    		nextIndex["Tool"] = currentIndex["Tool"]
    		currentIndex["Tool"] = nil
    	end
    end
    inputOrder[1]["Tool"] = Child

@ThatTimothy; @MayorGnarwhal

I’m slowly but surely getting there.
As you can see - It successfully takes up Slot1; however, it also occupies and replaces Slot3:

https://gyazo.com/eb01677926967f53665d93a0cda5c0f9

			for i = 1, #inputOrder - 1 do wait()
		    	local currentIndex = inputOrder[i]
		    	local nextIndex = inputOrder[i + 1]
		    	if currentIndex["Tool"] ~= nil and currentIndex["Tool"] == not currentIndex["Tool"] then
		    		nextIndex["Tool"] = currentIndex["Tool"]
		    		currentIndex["Tool"] = nil
					break
		    	end
				inputOrder[1]["Tool"] = Child
		    end

@ThatTimothy; @MayorGnarwhal; @Eandvwigle

I’ve “DONE” it!
Not in the way I would of liked but it’s a start!

		if isNew == true then
			if Child.Name == "Tool" then
				local Ex1 = inputOrder[1]["Tool"]
				local Ex2 = inputOrder[2]["Tool"]
				local Ex3 = inputOrder[3]["Tool"]
				local Ex4 = inputOrder[4]["Tool"]
				local Ex5 = inputOrder[5]["Tool"]
				
				print(inputOrder[1]["Tool"], inputOrder[2]["Tool"], inputOrder[3]["Tool"])
				
				inputOrder[1]["Tool"] = Child
				inputOrder[2]["Tool"] = Ex1
				inputOrder[3]["Tool"] = Ex2
				inputOrder[4]["Tool"] = Ex3
				inputOrder[5]["Tool"] = Ex4
				
				print(inputOrder[1]["Tool"], inputOrder[2]["Tool"], inputOrder[3]["Tool"])
1 Like