View topic - Sorting a list for max value



All times are UTC + 1 hour


Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: 09 Feb 2011, 05:24 
Blood & Steel Developer
User avatar

Joined: 25 Aug 2004, 12:31
Location: Has not played *a in years.
I can of modified an example I saw elsewhere.
What I want to find the teamID entry with the highest score. Would this work for lets say list score where score[teamID] - score values (in numbers)?


Code:
local function findwinner(score)
   local winner = 1   --index of max value
   local m = score[winner]         --max value
   for i, val in ipairs(score) do      --can use pairs() as well, ipairs() indicates an array-like table
      if val > m then
         winner = i
         m = val
      end
   end
   return m, winner   --neat feature of lua, can return multiple values
end


Top
 Offline Profile  
 
PostPosted: 09 Feb 2011, 05:49 
Moderator
User avatar

Joined: 22 Feb 2006, 01:02
Location: cheap kitchen
your code should work i think, whats wrong with it?
it can only find one winner though, does not work for a tie.
If you use better names for your variables, it gets much easier to read your code. ie "m" -> highestscore_sofar etc
---
spring tanks -> gadgets\tp_gamelogic.lua
Code:
function winningteams(score)
   local highestscore=0
   for teamid,_  in pairs (score) do
         if (score[teamid] > highestscore) then highestscore=score[teamid] end
   end
   local winners = {}
   for teamid,_  in pairs (score) do
      if (score[teamid] == highestscore) then table.insert(winners,teamid) end
   end
   return winners
end
In the first loop I look for the highest score.
In the second loop I check which team's score is equal to the highest score.
It is in two loops because multiple teams might have the same score (tie)


Top
 Online Profile  
 
PostPosted: 09 Feb 2011, 05:56 
User avatar

Joined: 28 Jul 2008, 05:51
Location: Australia
Code:
local teams = {'team1','team2','team3'}
local scores = {
  team1 = 100,
  team2 = 200,
  team3 = 300
}

-- Returns a shallow copy of t so changes to basic values won't affect the original (see also deepcopy).
function table.copy(t)
  local copy = {}
  for k,v in pairs(t) do
    copy[k] = v
  end
  return copy
end

-- returns a copy of teams sorted
local function SortTeamsByScore()
  -- a local function inside a function for speed
  local function HighestScore(teamA,teamB)
    return scores[teamA] > scores[teamB]
  end
  local sortedTeams = table.copy(teams)
  table.sort(sortedTeams, HighestScore)
  return sortedTeams
end


This code may look complicated but the key to it is the built-in Lua function table.sort. This function takes an array and a comparison function and runs the comparison on pairs of values to determine which comes first. It is the fastest method, especially on large lists.

The table copy stuff is only relevant if you don't want to change the order in the original table - otherwise just sort teams 'in-place' for even more speed.

Method 2:
If you are only interested in the highest score there is an even faster way
Code:
local teamScores = {
  [100] = 'team1',
  [300] = 'team2',
  [200] = 'team3'
}
local scores = {100,300,200}

local highestScore = math.max(unpack(scores))
local bestTeam = teamScores[highestScore]


This works because math.max can take an unlimited number of arguments and unpack converts the table into arguments. It fails in the event of 2 teams having the same score.


Last edited by SpliFF on 09 Feb 2011, 06:09, edited 1 time in total.

Top
 Offline Profile  
 
PostPosted: 09 Feb 2011, 06:07 
Moderator
User avatar

Joined: 22 Feb 2006, 01:02
Location: cheap kitchen
SpliFF:
what if there is a tie?


Top
 Online Profile  
 
PostPosted: 09 Feb 2011, 06:11 
User avatar

Joined: 28 Jul 2008, 05:51
Location: Australia
in a tie it returns one of the tied teams (the last one written to the list).


Top
 Offline Profile  
 
PostPosted: 09 Feb 2011, 06:49 
Moderator
User avatar

Joined: 22 Feb 2006, 01:02
Location: cheap kitchen
yes, thats what i meant.
It should not declare a "random" team as winner.


Top
 Online Profile  
 
PostPosted: 09 Feb 2011, 21:32 
Cursed Zero-K Developer
User avatar

Joined: 07 Nov 2007, 21:48
Location: Horse
Be careful with these solutions. In my experience this won't work correctly (but someone correct me if I'm wrong). The reason being, you should only sort an ordered table (the kind you use with ipairs() ). If your table is indexed by teamID (you use pairs() on it), and then the table you're getting back will not output sorted when you run it through pairs().

What I do is first put the key and value of the table into a new table like so:

Code:
table2 = {}
for k,v in pairs(table1)
  table2[#table2+1] = {k,v}
end


then sort table2 with this method:

Code:
local function Sortfunc(v1,v2)
    return v1[2] > v2[2]
end
table.sort(table2, Sortfunc)


then use ipairs() on the new table:

Code:
for _,val in ipairs(table2) do
  local k, v = val[1], val[2]
  -- do stuff with k and v which correspond to table1.
end


Top
 Offline Profile  
 
PostPosted: 09 Feb 2011, 23:23 
Spring Developer
User avatar

Joined: 28 Jun 2007, 06:30
what car said is true.
Tables in Lua are split in 2 parts: an array (index:1..n) and a list (= hashtable).
Now iterating the array is 'stable'. But the list one is NOT, that's because it uses the hashvalues of indices to find the values in it and those can differ between run instances. E.g. the hash of a table is the pointer to the memory location in RAM, and this obviously runtime dynamic. That's why you should NEVER EVER use pairs() on tables with tables as indices in synced code!!!
So if you need an ordered table then use only indices 1..n w/o any holes in it (cause of: 1..3 + 5..7 = array<1,2,3> + hashtable<5,6,7>).


Top
 Offline Profile  
 
PostPosted: 10 Feb 2011, 17:50 
Moderator
User avatar

Joined: 22 Feb 2006, 01:02
Location: cheap kitchen
That all seems very complicated, tables in tables just to find player with highest score at game end?
Is there something similiar wrong with my version? So far it doesnt look like it.


Top
 Online Profile  
 
PostPosted: 24 Aug 2011, 16:46 
User avatar

Joined: 23 Feb 2009, 16:29
Location: Finland
Can't you just use dictionary tables all the way and not iterate but lookup each time? The problem with ipairs is that it starts on 1, and that prevents you from making a table indexed by player id for example, because then it missed player id 0. Of course you could add 1 to each player id to get index, but then you can't copy and paste objects from one code to another.


Top
 Offline Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: Bing [Bot] and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group

Site layout created by Roflcopter et al.