Iterating through a dictionary in seemingly random order

Ranks Module

local module = {}

module.ranks = {
	['Noob'] = {0, Color3.fromRGB(100, 100, 100)},
	['Amateur'] = {10, Color3.fromRGB(143, 143, 143)},
	['Novice'] = {50, Color3.fromRGB(143, 211, 255)},
	['Super'] = {100, Color3.fromRGB(255, 148, 98)},
	['Awesome'] = {200, Color3.fromRGB(92, 170, 40)},
	['Experienced'] = {500, Color3.fromRGB(64, 110, 127)},
	['Impressive'] = {1000, Color3.fromRGB(255, 187, 69)},
	['Skilled'] = {1500, Color3.fromRGB(79, 255, 94)},
	['Expert'] = {2500, Color3.fromRGB(65, 166, 255)},
	['Insane'] = {5000, Color3.fromRGB(198, 52, 255)},
	['Professional'] = {10000, Color3.fromRGB(0, 0, 255)},
	['Outrageous'] = {25000, Color3.fromRGB(72, 58, 127)},
	['Legendary'] = {50000, Color3.fromRGB(255, 182, 35)},
	['Beast'] = {75000, Color3.fromRGB(63, 255, 34)},
	['Godly'] = {100000, Color3.fromRGB(255, 15, 15)},
}

return module

Seperate ServerScript

local ranksModule = require(ranks)
		for i, v in pairs(ranksModule.ranks) do
			if myData.tags >= v[1] then
				print(player.Name, 'Got enough tags for: ' .. i)
				myData.rank = i
				local rankValue = player.PlayerFolder:WaitForChild('Rank')
				if rankValue then
					rankValue.Value = myData.rank
				end
			end
		end

When a player has 50 tags, it prints that they have enough for:
Noob
Novice
Amateur
In that order, even though Amateur should be above Novice. Basically the higher the players tags, the higher their ranking should be. Thought if the I put the dictionary in order it would itterate through it in order, but for some reason it doesn’t

1 Like

Dictionaries never iterate “in order”. Dictionaries have an undefined order. If you want to go through a dictionary in a specific order then you need to convert it to an array first or you can just use an array from the start.


Here’s an example using arrays from the start:

local module = {}

module.ranks = {
	{'Noob', 0, Color3.fromRGB(100, 100, 100)},
	{'Amateur', 10, Color3.fromRGB(143, 143, 143)},
	{'Novice', 50, Color3.fromRGB(143, 211, 255)},
	{'Super', 100, Color3.fromRGB(255, 148, 98)},
	{'Awesome', 200, Color3.fromRGB(92, 170, 40)},
	{'Experienced', 500, Color3.fromRGB(64, 110, 127)},
	{'Impressive', 1000, Color3.fromRGB(255, 187, 69)},
	{'Skilled', 1500, Color3.fromRGB(79, 255, 94)},
	{'Expert', 2500, Color3.fromRGB(65, 166, 255)},
	{'Insane', 5000, Color3.fromRGB(198, 52, 255)},
	{'Professional', 10000, Color3.fromRGB(0, 0, 255)},
	{'Outrageous', 25000, Color3.fromRGB(72, 58, 127)},
	{'Legendary', 50000, Color3.fromRGB(255, 182, 35)},
	{'Beast', 75000, Color3.fromRGB(63, 255, 34)},
	{'Godly', 100000, Color3.fromRGB(255, 15, 15)},
}
local ranksModule = require(ranks)
for _, v in pairs(ranksModule.ranks) do
	if myData.tags >= v[2] then
		print(player.Name, 'Got enough tags for: ' .. v[1])
		myData.rank = v[1]
		local rankValue = player.PlayerFolder:WaitForChild('Rank')
		if rankValue then
			rankValue.Value = myData.rank
		end
	end
end

If you convert it to an array instead of using arrays from the start, then you’ll need some sort of property in the dictionary to sort by, such as a rank index, a name, etc. Dictionaries never keep the order you give them, so after converting to an array you have to sort it to get it ordered.

Here’s an example with converting to array:

local module = {}

module.ranks = {
	['Noob'] = {0, Color3.fromRGB(100, 100, 100)},
	['Amateur'] = {10, Color3.fromRGB(143, 143, 143)},
	['Novice'] = {50, Color3.fromRGB(143, 211, 255)},
	['Super'] = {100, Color3.fromRGB(255, 148, 98)},
	['Awesome'] = {200, Color3.fromRGB(92, 170, 40)},
	['Experienced'] = {500, Color3.fromRGB(64, 110, 127)},
	['Impressive'] = {1000, Color3.fromRGB(255, 187, 69)},
	['Skilled'] = {1500, Color3.fromRGB(79, 255, 94)},
	['Expert'] = {2500, Color3.fromRGB(65, 166, 255)},
	['Insane'] = {5000, Color3.fromRGB(198, 52, 255)},
	['Professional'] = {10000, Color3.fromRGB(0, 0, 255)},
	['Outrageous'] = {25000, Color3.fromRGB(72, 58, 127)},
	['Legendary'] = {50000, Color3.fromRGB(255, 182, 35)},
	['Beast'] = {75000, Color3.fromRGB(63, 255, 34)},
	['Godly'] = {100000, Color3.fromRGB(255, 15, 15)},
}

return module
local ranksModule = require(ranks)

local sortedRanks = {}
for k, v in pairs(ranksModule.ranks) do
	table.insert(sortedRanks, {k, v})
end

table.sort(sortedRanks, function(a, b)
	return a[2][1] < b[2][1]
end)

for _, pair in pairs(sortedRanks) do
	local rankName, info = pair[1], pair[2]
	if myData.tags >= info[1] then
		print(player.Name, 'Got enough tags for: ' .. rankName)
		myData.rank = rankName
		local rankValue = player.PlayerFolder:WaitForChild('Rank')
		if rankValue then
			rankValue.Value = myData.rank
		end
	end
end

Clearly, using an array from the start is easier!

10 Likes

You can then use a metatable to allow you to use it like a dictionary.

https://www.lua.org/pil/13.4.1.html

2 Likes

I had the same issue once and never found out why it didn’t work. Thanks for the reason, solution & alternative. Shame it doesn’t work with dictionaries, they look so good!

Good post!

Love me some metatables