Bubba911
Bubba911

Reputation: 53

Lua Table Sorting 2 compares

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

Answers (2)

greatwolf
greatwolf

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

Yu Hao
Yu Hao

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

Related Questions