How to sort stringed ids in specific order

I am wanting to order my block ids in a way that keeps them clean in a grid layout. However, cause my block ids can include : or even letters, it makes laying them out incredbily confusing.

Example of ids

local BlockIds = {
	["1"] = 1,
	["3"] = 2,
	["3:1"] = 3,
	["3:1a"] = 4,
	["4"] = 5,
	["7b"] = 6,
	["8:12"] = 7,
	["9"] = 8
}

IGNORE the values, just there for sake of how i lay my ids out. Only thing important is the string.

I need that table of BlockIds to be in the order they are arranged. So a blockid or 3:1 should go BEFORE 3:1a, and AFTER 3

local Layout = string.gsub(NewBlock:GetAttribute("Id"), "%D", "")
	local Concat = "00"
	
	if string.find(blockId, ":") then
		Layout = string.sub(blockId, 1, string.find(blockId, ":")  - 1)
		
		local PostNumber = string.sub(blockId, string.find(blockId, ":") + 1)
		Concat ..= PostNumber
	end
	
	if string.find(blockId, "a") then -- Slab
		Concat = Concat .. "1"
	elseif string.find(blockId, "b") then -- Stair
		Concat = Concat .. "2"
	elseif string.find(blockId, "c") then -- Corner Stair
		Concat = Concat .. "3"
	elseif string.find(blockId, "d") then -- Inner Stair
		Concat = Concat .. "4"
	end
	
	NewBlock.LayoutOrder = tonumber(Layout .. Concat)

Kind of a mess of what I have, it doesn’t really work. I was thinking of just adding a bunch of 0’s and then changing as necessary.

Basically, visualized it should be

local BlockIds = {
	["1"] = 1,
	["2"] = 2,
	["3:1"] = 3,
	["3:1a"] = 4,
	["4"] = 5,
	["7b"] = 6,
	["8:12"] = 7,
	["9"] = 8
}

-- what it should look like when converted:
local BlockIds = {
	["10000"] = 1,
	["20000"] = 2,
	["30010"] = 3,
	["30011"] = 4,
	["40000"] = 5,
	["70002"] = 6,
	["80120"] = 7,
	["90000"] = 8
}

Basically the blocks main id first, a 0 after to pad out. then 2 0’s (to take into account anything that might be after : ) and then another 0 for any lettered ids.

Don’t you use ipairs to loop through them?

They can’t be sorted in an order cause they a dictionary

Managed to figure it out

local Layout = string.gsub(blockId, "%D", "")
local Concat = "000"

if string.find(blockId, ":") then
	Layout = string.sub(blockId, 1, string.find(blockId, ":") - 1)
	
	local AfterNumber = string.gsub(string.sub(blockId, string.find(blockId, ":") + 1), "%D", "")
	if tonumber(AfterNumber) < 10 then -- Single digit
		Concat = "00" .. AfterNumber
	else -- 2 digits
		Concat = "0" .. AfterNumber
	end
end

if string.find(blockId, "a") then -- Slab
	Concat ..= "1"
elseif string.find(blockId, "b") then -- Stair
	Concat ..= "2"
elseif string.find(blockId, "c") then -- Corner Stair
	Concat ..= "3"
elseif string.find(blockId, "d") then -- Inner Stair
	Concat ..= "4"
else
	Concat ..= "0"
end

NewBlock.LayoutOrder = tonumber(Layout .. Concat)
1 Like

You can also take advantage of string.split() passing in your colon separator to get a table with the before and after number.

A neater way to do it instead of a bunch of if-else statements would be to make a table with each letter and what the corresponding value should be. Then loop through the table and check for the letter.

local values = {
    ["a"] = "1",
    ["b"] = "2",
    ["c"] = "3",
    ["d"] = "4"
}