I have stumbled upon a strange behavior of table.sort()
, in which the comparing function is invoked by passing the same array element in both parameters.
Consider the code below. I want to sort the array from highest to lowest value of the property v
and, in case they are equal (and since table.sort()
algorithm is not stable as of the docs), I want to sort them by the original indices of the elements.
-- The array to sort
local arr = {
{id="A", v = 1},
{id="B", v = 1},
{id="C", v = 0},
{id="D", v = 1},
{id="E", v = 1}
}
-- A map containing the original index of the elements in the array: element => originalIndex
local original_indices = {}
for index, elem in ipairs(arr) do
original_indices[elem] = index
end
-- Sort the array
table.sort(arr,
function(a, b)
assert(a ~= b, "Comparing the same element in the array!")
-- Compare the value
if a.v > b.v then
return true
elseif a.v < b.v then
return false
end
-- Values are equal. Compare original indices, which should always
-- decide the final order.
local ia = original_indices[a]
local ib = original_indices[b]
if ia < ib then
return true
elseif ia > ib then
return false
end
error("BUG! Comparing the same element in the array!")
end
)
The expected result should be:
{
{id="A", v = 1},
{id="B", v = 1},
{id="D", v = 1},
{id="E", v = 1},
{id="C", v = 0}
}
But, instead, I get an error because Lua is invoking the sorting function by passing the same element in both parameters, which should not.
Am I missing something? How can I get the expected result?
You can play around with the code here.
To solve your problem, simply return when comparing the same element.
if a == b then
return
end
Internally the sorting algorithm of Lua is the quick sort of Hoare partition scheme. During partitioning, the pivot value will compare each element one by one from each side until it finds the element with the same or opposite value, so there is a chance that the same element is compared.