Table.sort issues

I have function, that rearranged elements by price. But table.sort goes crazy for second day, and I cant even find any reason for it to do so.

function vehicleManager:Sort()
	local items = Container:GetChildren()
	
	table.sort(items, function(a: TextButton, b: TextButton) 
		print(a, b)
                -- here I had comparing part
		return true
	end)

	for _, item in items do
		item.Parent = Container
	end
end

I was trying to find reason for issue, debugging values, (if some are nil), rewritten it in different way. At the end, I have completely removed checks and did just return true and it still throws an error after particular instance.

Also, just in case, this is code where I was comparing prices:

function vehicleManager:Sort()
	local items = Container:GetChildren()
	
	table.sort(items, function(a: TextButton, b: TextButton) 
		print(a, b)
		
		if a:IsA("TextButton") and b:IsA("TextButton") then
			-- this part gets tables with vehicle data, including price
			local aVeh = vehicles:GetCarByID(a.Name)
			local bVeh = vehicles:GetCarByID(b.Name)

			--- compares
			return aVeh.Price < bVeh.Price
		else
			return true
		end
	end)

	for _, item in items do
		item.Parent = Container
	end
end

Guys, please help, as I have been sitting on this for second day. I already used table.sort before, but it worked normally ¯_(ツ)_/¯

You could add some prints and print out aVeh and bVeh and make sure they have the values you expect. The error above typically happens when there is an inconsistency. For the example of always returning true, that would be inconsistent because you need it to return true when say a < b but it also needs to make sure it returns false when a >= b.

1 Like

Hello, If I get everything right, the error message you’re getting, “invalid order function for sorting,” means that the function provided to table.sort isn’t satisfying the conditions for a “strict weak order.” Specifically, it isn’t consistent in the way it orders elements. This is most likely because your function doesn’t handle all possible comparisons correctly. In your original function, you returned true even if a and b are not TextButtons. This means that any time Lua tries to sort a TextButton and a non-TextButton, it will think that TextButton should always come first, regardless of the actual value of the non-TextButton. This can lead to situations where a < b, b < c, and yet c < a, which is inconsistent and will cause table.sort to fail.

Here’s a revised version of your function that should be more consistent:

function vehicleManager:Sort()
	local items = Container:GetChildren()
	
	table.sort(items, function(a, b) 
		if a:IsA("TextButton") and b:IsA("TextButton") then
			local aVeh = vehicles:GetCarByID(a.Name)
			local bVeh = vehicles:GetCarByID(b.Name)

			return aVeh.Price < bVeh.Price
		else
			-- non-TextButtons always come last
			if a:IsA("TextButton") then
				return true
			else
				return false
			end
		end
	end)

	for _, item in ipairs(items) do
		item.Parent = Container
	end
end

Note that we’re using ipairs in the for-loop. This is because table.sort works on sequences – tables where the keys are consecutive integers. When you use pairs with sorted table, the order may not be guaranteed. With ipairs, you’ll iterate over the table in order.

This version of the function always puts TextButtons before non-TextButtons, and within those two groups, it sorts by price. This should give you consistent ordering and avoid the error message.

Please also ensure that the method GetCarByID() is always returning a table with a Price field. If there are any nil prices or any car IDs that don’t correspond to an actual car, you could still get unexpected results.

1 Like

That seems to work, but more one question. If I want to add Gamepass check there (for gamepassed cars to go down of the list), where i have to put check for it? I mean, gamepass is defined by simple aVeh.Gamepass and bVeh.Gamepass (nil in gamepass is not required), but all my attempts leaded to the same problems.

If you want to sort the vehicles such that those requiring a gamepass appear lower in the list than those that don’t, you can extend your sorting function to consider the Gamepass field. You’ll first check whether the vehicles require a gamepass. If they have the same requirement (either both need a gamepass or neither does), you’ll then compare their prices.

table.sort(items, function(a, b) 
	if a:IsA("TextButton") and b:IsA("TextButton") then
		local aVeh = vehicles:GetCarByID(a.Name)
		local bVeh = vehicles:GetCarByID(b.Name)

		-- Check for the existence of the Gamepass field.
		-- We assume that if it's nil, the car doesn't require a gamepass.
		local aGamepass = aVeh.Gamepass or false
		local bGamepass = bVeh.Gamepass or false

		-- If one requires a gamepass but the other doesn't, the one that doesn't should come first.
		if aGamepass and not bGamepass then
			return false
		elseif not aGamepass and bGamepass then
			return true
		else
			-- If both or neither require a gamepass, sort by price.
			return aVeh.Price < bVeh.Price
		end
	else
		-- non-TextButtons always come last
		if a:IsA("TextButton") then
			return true
		else
			return false
		end
	end
end)

This modification ensures that cars not requiring a gamepass are listed first, followed by those requiring a gamepass, with cars in each category being sorted by price. Please ensure that the Gamepass field is either a boolean or nil. If the field can hold other values, you might need to adjust the function accordingly.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.