How to get table in the order it's written in

Knight = {
		['Claymore'] = {
			Cost = 100,
			Currency = 'Gold'
		},
		['Highlander'] = {
			Cost = 200,
			Currency = 'Gold'
		},
		['Light'] = {
			Cost = 250,
			Currency = 'Gold'
		},
}

But when I go

for i, item in pairs(classItems.Weapons[selectedClass]) do
    print(i)
end

It will print like
Highlander
Light
Claymore
Which is not the order I put them in in the table. Is there anyway for it to just return the actual order they are in the table?

5 Likes

If you’re looking to preserve order, you’ll need to use a table with numerical indexes (an array). Tables with string indexes will not preserve declaration order.

You could keep an array that contains (in order) each table inside the Knight table, but if you need to do this, odds are your code and/or data structure could be reworked to avoid this problem. Can you explain at a higher level what you’re trying to do?

3 Likes

Basically the point of this is the for loop gets each item in the table to create a button for them in the shop. But each item in the table is stored so the cheapest item is higher in the table, most expensive at the bottom, etc.

But atm, it just grabs a random one, which means the shops order is a mess with all the items just in random spots.

You suggesting something like this?

Knight = {
    [1] = {
        Name = 'Claymore',
        Cost = 100,
        Currency = 'Gold'
    },
-- etc..
}
1 Like

I would not recommend that, no. That’s why I asked for more detail.

You could use a UIListLayout or UIGridLayout with the SortOrder property set to Enum.SortOrder.LayoutOrder to automatically reorder the buttons according to the LayoutOrder property set on each button. Simply set the LayoutOrder value to the price.

1 Like

I already have that :sweat_smile:

But since it’s creating the buttons in the wrong order, it means the layout of it will be wrong anyway. The for loop isn’t getting the order of the table, thus the order of the buttons is wrong

UIGridLayout with SortOrder set to LayoutOrder, for example, will automatically reorder the list according to the LayoutOrder set on the buttons contained within the same GUI instance as the UIGridLayout. Declaration order of the list in your code and button creation order don’t matter.


Full table

	Knight = {
		['Claymore'] = {
			Cost = 100,
			Currency = 'Gold'
		},
		['Highlander'] = {
			Cost = 200,
			Currency = 'Gold'
		},
		['Light'] = {
			Cost = 250,
			Currency = 'Gold'
		},
		['Long Sword'] = {
			Cost = 500,
			Currency = 'Gold'
		},
		['Trusty'] = {
			Cost = 50,
			Currency = 'Gems'
		},
		['Riptide'] = {
			Cost = 100,
			Currency = 'Gems'
		},
		['Shai'] = {
			Cost = 200,
			Currency = 'Gems'
		},
		['Judgement'] = {
			Cost = 250,
			Currency = 'Gems'
		},
	},

UIListLayout is set to LayoutOrder.

So idk whats going on, but the buttons aren’t being created in order, nor do they seem to be placed in order

Are you thoroughly reading my replies? In the screenshot you’ve attached I can very clearly see you have not set the LayoutOrder property of your buttons, as it’s still 0 for every single one of them.

Problem with setting price is the different currency.

500 Gold should be higher on the list than 50 Gems

You could try multiplying gem prices by a large value when setting LayoutOrder.

How could I set the Price to be the value? Naming the buttons the cost? If so then that would make referencing the buttons a nightmare. They are named after their item name so it’s easy to reference

Gold currency:
Button.LayoutOrder = data.Cost
Gem currency:
Button.LayoutOrder = data.Cost * 5000 or some large value to scale gem prices so they’re always valued as more expensive than gold prices.

1 Like

Ohhhh I did not realise there was a LayoutOrder property…

You can’t preserve the “order it’s written in” with tables like this:

tbl = {
    ['Item1'] = 'a',
    ['Item2'] = 'b',
    ['Item3'] = 'c',
}

(This can come out in any order. This is called a dictionary. ‘Item1’, ‘Item2’, etc. are Keys.)

You can only preserve the “order it’s written in” with these types of tables:

tbl = {
    [1] = 'a',
    [2] = 'b',
    [3] = 'c',
}

AKA

tbl = {'a', 'b', 'c'}

(This comes out in a defined order. This is called an array. 1, 2, etc. are Indexes.)


You have three ways around this:

  1. Store things in a dictionary (example 1), then create an array from it and sort it afterwards.
  2. Store things in a dictionary (example 1), then use LayoutOrder set to Cost to automatically show them in sorted order
  3. Store in an array (example 2)

You already get how to do 2 and 3. I figure I’d chime in and explain how to do #1:

-- Step 1: Add 'Name' values to everything so that we know their names when in an array
for key, item in pairs(Knight) do
	item.Name = key
end

-- Step 2: Make a sorted array
-- Step 2.1: Add everything to an array
local array = {}
for key, item in pairs(Knight) do
	table.insert(array, item)
end
-- Step 2.2: Sort it
table.sort(array, function(a, b)
	-- a and b are two items
	-- we need to return if a is "smaller than" b
	return a.Cost < b.Cost
end)
-- Now `array` is your items in correct order!
Some additional example snippets to help you learn sort functions
-- Sort by Cost, with largest first instead of smallest first:
table.sort(array, function(a, b)
	return a.Cost > b.Cost
end)
-- Sort by name
table.sort(array, function(a, b)
	return a.Name < b.Name
end)
-- Sort by Cost, and use infinity if it lacks a cost
table.sort(array, function(a, b)
	local aCost = a.Cost
	if aCost == nil then
		aCost = math.huge
	end
	local bCost = b.Cost
	if bCost == nil then
		bCost = math.huge
	end
	return aCost < bCost
end)

-- More concise version:
table.sort(array, function(a, b)
	return (a.Cost or math.huge) < (b.Cost or math.huge)
end)
-- Sort by Currency, giving each Currency a custom priority value
local CurrencyOrder = {
	['Gems'] = 1,
	['Gold'] = 2,
	['Souls'] = 3,
}

table.sort(array, function(a, b)
	return CurrencyOrder[a.Currency] < CurrencyOrder[b.Currency]
end)
-- Sort by Cost if the Currency is the same, or by Currency otherwise
-- This will group items together by currency
local CurrencyOrder = {
	['Gems'] = 1,
	['Gold'] = 2,
	['Souls'] = 3,
}

table.sort(array, function(a, b)
	if a.Currency ~= b.Currency then
		return CurrencyOrder[a.Currency] < CurrencyOrder[b.Currency]
	else
		return (a.Cost or math.huge) < (b.Cost or math.huge)
	end
end)
-- Sort by "Value", where each currency has a value multiplier on the cost
-- This will group items together by currency
local CurrencyValues = {
	['Gold'] = 1,
	['Gems'] = 2,  -- worth 2x as much as gold
	['Souls'] = 4, -- worth 4x as much as gold
}

table.sort(array, function(a, b)
	local aMultiplier = CurrencyValues[a.Currency]
	local aCost = a.Cost or math.huge
	local aValue = aCost*aMultiplier

	local bMultiplier = CurrencyValues[b.Currency]
	local bCost = b.Cost or math.huge
	local bValue = bCost*bMultiplier

	return aValue < bValue
	-- we could have condensed that into one line, but it would be a hard-to-read-mess!
end)

With this method, once you get it sorted, you can just use the index of each item in the array (aka i) for the LayoutOrder.


If you just need something simple, then setting the LayoutOrder directly as qqtt991 suggested is smarter. If you need to group together items by currency or other complex logic, then using table sort functions can be very useful.

11 Likes

I can remember reading somewhere that ipairs returns the order that the table is in. Here is an example:

local Table = {"One","Two","Three","Four"}

for i,v in ipairs(Table) do
	print(v)
end

-- Output
--One
--Two
--Three
--Four
1 Like

Set your UIGridLayout type to be LayoutOrder, Previously: “Name”.

then in the buttons too can make a layout order whatever you want, you can also use this in scripts if thats what your looking for.

2 Likes

The poster is not using an array. It’s a dictionary. (String keys)

2 Likes