Reputation: 53
I have gone over as many of the answers here as I could find that had titles I considered near enough to my problem to look into. I haven't seen anyone having my exact issue, so I'm asking a question I hope is just me being ignorant to a simple fact.
I'm trying to code a table that records HP (int) and the distance (boolean) and then sort by HP with only the ones in Range near the top.
local tableTest = {
{hp = 64, range = true, name="Frank"},
{hp = 100, range = true, name="Joe"},
{hp = 2, range = false, name="Jim"},
{hp = 76, range = true, name="Tim"},
{hp = 17, range = false, name="Jill"},
{hp = 16, range = true, name="Phillip"},
}
-- Sort by HP and Range to find lowest Unit in Range.
table.sort(tableTest, function(x,y) return x.hp < y.hp and x.range end)
for i=1, #tableTest do print(tableTest[i].name, tableTest[i].hp) end
The output for this is:
Phillip 16
Jim 2
Frank 64
Jill 17
Tim 76
Joe 100
The output I was expecting from this would be:
Phillip 16
Frank 64
Tim 76
Joe 100
Jim 2
Jill 17
I pray this is just a misunderstanding on my part of how the table.sort works with multiple checks like this (I assumed it was closer to how you declare a variable like this).
edit
Additional information - If I change the order of where the range=false
indexes are located in the table, the output changes as well (still incorrect). The values just sort themselves into different indexes after the sort.
Upvotes: 5
Views: 697
Reputation: 20878
You already got an answer to this question but I think it's worth adding another one here that covers how you can reason about this logic easier. The ideas presented here are really language agnostic.
The purpose of providing a comparison function is really to answer one question: Should x come before y? Another way to ask the same question is, does x have a higher precedence then y? Often you implement this with the same ordering properties as say the <
operator.
So your function should return true
only if x definitely precedes y. In your case, you are really sorting by the range
field first and if they both happen to be true then use the hp
field as a "tie-breaker".
You can construct a truth table here to help you find the most concise way to express the logical condition that yields the behavior you're looking for:
x | y | x before y?
-------------------------
T | T | x.hp < y.hp
T | F | T
F | T | F
F | F | F
Your original condition x.hp < y.hp and x.range
is close but not quite correct for all possible cases.
Above we see that if x is false then the final outcome is also false regardless of what y is. So y is only considered when x is true. Lastly, to avoid the caveat of a falsey condition in the logic short-circuit in lua we'll want x.hp < y.hp
to be at the end of the logical expression. Thus, the logical condition you're looking for is:
return x.range and (not y.range or x.hp < y.hp)
Upvotes: 0
Reputation: 122493
According to your description, your order function needs to compare range
first, then compare hp
.
table.sort(tableTest, function(x,y)
if x.range and y.range then return x.hp < y.hp
elseif x.range then return true
elseif y.range then return false
else return x.hp < y.hp end
end)
Maybe there is some shorter version, but this one sure works and the logic is clear.
Upvotes: 4