Table.sort Not using the sorting function?

I have been trying to sort player - teams on a custom leaderboard script, but I tried doing table.sort and it is seeming to even run the function given.
What I would like to happen is that the player will be sorted under the team that the player is on.

This is my code:

local Players = game:GetService("Players")

function sortPlayerEntries(a, b)
print("Sorting.")
if a.Type == "Team" and b.Type == "Player" and Players:FindFirstChild(b.Name).Team.Name == a.Name then
return true
elseif a.Type == "Player" and b.Type == "Player" then
return true
elseif a.Type == "Player" and b.Type == "Team" and Players:FindFirstChild(a.Name).Team.Name == b.Name then
return false
end
end

tableb = {RussellSchutle = {Type = "Player", Name = "RussellSchutle"}, TeamA = {Type = "Team", Name = "TeamA"}, TeamB = {Type = "Team", Name = "TeamB"} }
table.sort(tableb,sortPlayerEntries)
for i,v in pairs(tableb) do
print(game:GetService("HttpService"):JSONEncode(v))
end

(Player is currently joined in TeamA)

What’s Expected to print:
> {Type = “Team”, Name = “TeamA”}
> {Type = “Player”, Name = “RussellSchutle”}
> {Type = “Team”, Name = “TeamB”}

Any questions please reply with it.

You are trying to sort a dictionary, but you can only sort arrays. A dictionary is when you can do tableb.RussellSchutle. An array is when you can do tableb[1].

Changing tableb to an array should fix this:

tableb = {{Type = "Player", Name = "RussellSchutle"}, {Type = "Team", Name = "TeamA"}, {Type = "Team", Name = "TeamB"}}
1 Like

I didn’t know that dictionary and arrays were different.

But in using the custom sorting function how would I define the difference between the first array and the second one.

I changed the dictionary to an array from the code above and it errors with

attempt to index a nil value [Line 5]

The good news is, your original issue is solved!

The bad news is that now you have to fix your sorting function!


I’m not sure what you mean by this. tableb is the array. You are sorting the contents of tableb. I’m going to call each thing inside tableb an “item”.

Each of these {Type = "Player", Name = "RussellSchutle"} is an item. Your sorting functions receives a and b, which are both items. You don’t know which items it will give you beforehand. Your sort function is supposed to return true if a belongs before b. How you define which items are supposed to go before other items is up to you.

In other words, your sort function is supposed to answer the question, “is a in front of b?”


The line that’s erroring is the following:

if a.Type == "Team" and b.Type == "Player" and Players:FindFirstChild(b.Name).Team.Name == a.Name then

with the following error: attempt to index a nil value [Line 5]

This means that one of the following things must be nil:

  • a
  • b
  • Players
  • Players:FindFirstChild(b.Name)
  • or Players:FindFirstChild(b.Name).Team

We don’t know which one is nil. If I were you, I’d add temporary prints to print all those things out so you can tell which ones are nil.

Some notes:

  • If your sort function is inconsistent, it will either error, or a or b will end up nil at some point. A sort function is inconsistent when it says that an item should be both before and after some other item at the same time. That’s not possible, so it breaks the sorter.
  • If there is no player in the game with the name b.Name then it will error.

I can tell you now that if you have a few players in the array, your sort function will error. It will first ask “is Player1 in front of Player2?” then ask “is Player2 in front of Player1?” You are returning yes (true) for both of those questions, which doesn’t make sense!

Could you elaborate on how exactly you want these player and team items sorted?


I’m guessing that these represent labels for each team or player, like how they would show on the player list. I’m also guessing that you want each player to be grouped with its team label. Additionally, I’m guessing that within each team you want to sort players by score or name and that you want each team group sorted by name.

The following is an example that puts all those guesses into practice:

local Players = game:GetService("Players")

function sortPlayerEntries(a, b)
	if a.Team == b.Team then
		if a.Type == b.Type then -- sort between two players on the same team
			return a.Name < b.Name -- sort names alphabetically
		else -- sort between player label and team label for the same team
			return a.Type == "Team" -- team labels always come first
		end
	else
		return a.Team < b.Team -- sort groups of team+player labels alphabetically by team name
	end
end

tableb = {
	{Type = "Player", Name = "RussellSchutle", Team = "TeamA"},
	{Type = "Team", Name = "TeamA", Team = "TeamA"},
	{Type = "Team", Name = "TeamB", Team = "TeamB"}
}
table.sort(tableb,sortPlayerEntries)
for i,v in pairs(tableb) do
	print(game:GetService("HttpService"):JSONEncode(v))
end

An “Array” is still a table, but all of its keys are sequential integers starting at 1. You can only sort tables structured like that. However, your issue is a little more obscure.

This is an unfortunate idiosyncrasy with table.sort — if you have inconsistent behavior from your sort function, you will get nils randomly thrown at you, as though you’re supposed to sort a nil value.

See: https://stackoverflow.com/questions/2102710/treating-nils-in-sort-function

It’s odd behavior. It makes no sense. It’s a pain to debug. But it always comes down to how you handle cases where two keys are relatively equivalent. If b sorts later than a, then a should never sort later than b. When in doubt, return false.

1 Like

Your solution is so far correct, I will insert it to my leaderboard script and see if it works.

Thanks for the help! :smile:

(Will mark as solution when It is working. May take couple hours due to chores.)