[LUA Question] sort key based table by value

[LUA Question] sort key based table by value

by Renew » Fri Apr 01, 2016 8:48 am

Hi devs,
i have a problem that i cant solve - googled like crazy :/
i want to sort a key based table by its values. example:
Code: Select all
table = {"Name1" = 5, "Name2" = 7, "Name3" = 1}

-> print with pairs() would give
Code: Select all
Name1 5
Name2 7
Name3 1


http://wowwiki.wikia.com/wiki/API_sort : pairsByKeys does sort only by names

what i want is a sort like this:

Code: Select all
Name2 7
Name1 5
Name3 1


atm i convert the table to a another num based table so i can use sort(), but that like cheap workarround
my Addons:
- Vanilla Healing Assignments - /viewtopic.php?f=63&t=23326
- Vanilla Storyline -
User avatar
Renew
Senior Sergeant
Senior Sergeant
 

Re: [LUA Question] sort key based table by value

by schaka » Fri Apr 01, 2016 11:07 am

It is, in fact, the only way possible. Lua cannot sort tables unless they have numeric indexes.
With Questie, we had the same problem. We tried everything, including a custom sorting function. Eventually we found an old WowWiki article stating that sorting will simply not be applied if you are using alphanumeric keys.
schaka
Senior Sergeant
Senior Sergeant
 

Re: [LUA Question] sort key based table by value

by Renew » Fri Apr 01, 2016 11:23 am

schaka wrote:It is, in fact, the only way possible. Lua cannot sort tables unless they have numeric indexes.


ty for this info, seems i have to stay with my "workarround" :)
my Addons:
- Vanilla Healing Assignments - /viewtopic.php?f=63&t=23326
- Vanilla Storyline -
User avatar
Renew
Senior Sergeant
Senior Sergeant
 

Re: [LUA Question] sort key based table by value

by AfterAfterlife » Mon Apr 04, 2016 10:28 am

If you want to sort tables effectively, for example, by name, id, time, whatever you want..., I recommend to use a matrix, i.e. tables inside a table.
Example:
Code: Select all
local matrix = {
   { name = "test", race = "orc", id = 5},  -- a table
   { name = "testing", race = "human", id = 1},  --another table...
   { name = "test100", race = "undead", id = 2},
}


With a table struct like that, you can now sort the matrix by name, race or id.

For example:
Code: Select all
--if false, then changes positions, if not, moves on. So, false if you want to change
local function compare(a, b)
   --a and b are tables inside the matrix
   if a.id > b.id then
      return false;
   else
      return true;
   end
end

table.sort(matrix, compare);


If you want to check the final result:
Code: Select all
for k,v in pairs(matrix) do
   print(k, v.name, v.race, v.id);
end


Dunno how complex is your table, but this should work in any case.
AfterAfterlife
Grunt
Grunt
 

Re: [LUA Question] sort key based table by value

by Renew » Mon Apr 04, 2016 11:02 am

AfterAfterlife wrote:If you want to sort tables effectively, for example, by name, id, time, whatever you want..., I recommend to use a matrix, i.e. tables inside a table.


this is very inefficient for cases you have 2 tables and you want to search for a value...
example: i made a roll addon for dkp: https://www.youtube.com/watch?v=K5ZP5diQv40&f

i have 10 ppl that roll on an item: 1. table has 10 names
and i have 200 ppl in he guild: 2. table has 200 names

i use
Code: Select all
for i=1,GetNumGuildMembers() do
to look through the guild for names -> then i have to do another for loop for the 1. table to compare names-> overall 200*10 = 2000 iterations

if i use a key instead i can have
Code: Select all
name, _, _, _, _, _, note = GetGuildRosterInfo(i)
if LER.RollList[name] then


-> 200 iterations instead = win of 1800 loops :)


what you posted is my workarround i use to sort the key table :)
my Addons:
- Vanilla Healing Assignments - /viewtopic.php?f=63&t=23326
- Vanilla Storyline -
User avatar
Renew
Senior Sergeant
Senior Sergeant
 

Re: [LUA Question] sort key based table by value

by AfterAfterlife » Mon Apr 04, 2016 11:45 am

If the problem is to check if the player that rolled is in your guild, it's better to have a table with all your guildmates with their names as keys, like you said. This could be created every time you login or when you join a raid.

Also, you should iterate in the opposite way, i.e. instead of searching for guildmembers in the 1. table, check if any player in the 1. table is in your guild. It saves a lot of iterations, because you do 10 ifs (# players that rolled) instead of 200 ifs (# guildmates).

Example:
Code: Select all
local rollTable = {
   { name = "test", roll = 87},
   { name = "testing", roll = 13},
   { name = "test100", roll = 54},
}

local guildTable = {
   ["test"] = 100,
   ["test100"] = 50,
   ["moreTests"] = 90,
}


Then you can use your method:
Code: Select all
for num, player in pairs(rollTable) do
   if(guildTable[player.name]) then
      --do something
   end
end


You can still sort the rolls, but not the DKP (from my guess, I think you are storing DKP values in your guildmates).
AfterAfterlife
Grunt
Grunt
 

Re: [LUA Question] sort key based table by value

by Renew » Mon Apr 04, 2016 12:08 pm

AfterAfterlife wrote:If the problem is to check if the player that rolled is in your guild, it's better to have a table with all your guildmates with their names as keys, like you said. This could be created every time you login or when you join a raid.


this doesnt work - the DKP values are stored in the guild notes...and they can change each boss :)

basically youre right, i could save names and DKP in a table and loop the 1. table with all rollers (less loops)
but in the end it would be more effort, because i have to loop and save the guildinfos before :)
my Addons:
- Vanilla Healing Assignments - /viewtopic.php?f=63&t=23326
- Vanilla Storyline -
User avatar
Renew
Senior Sergeant
Senior Sergeant
 

Re: [LUA Question] sort key based table by value

by AfterAfterlife » Mon Apr 04, 2016 12:49 pm

Renew wrote:this doesnt work - the DKP values are stored in the guild notes...and they can change each boss :)

If it's an addOn that updates the DKP after each boss kill, then the solution here is to update your guildTable as well. You don't need to update all your guildTable (i.e. check offline players), instead you just update your raid members that are guild members too.

Renew wrote:basically youre right, i could save names and DKP in a table and loop the 1. table with all rollers (less loops)
but in the end it would be more effort, because i have to loop and save the guildinfos before :)


The guild infos are just stored in the beginning or updated when you kill a boss, like I said above. Storing/reading values in local variables is way faster than calling functions, for example: GetGuildRosterInfo.

It all leads to memory space vs cpu time. You can save all your guild info in a table to quickly access after (downside: wasting 2 or 3 KBytes) or you can call 200 times the functions GetGuildRosterInfo + GetNumGuildMembers everytime you kill a boss (downside: takes more cpu time).

Example:
1) You join a raid - creates a table with guildmates
2) Your raid killed a boss - DKP AddOn updates values
3) RollAddOn checks if there are guild members in your raid (max: 40 [i]ifs), if yes stores new values in the guildTable.[/i]
4) You start a roll - saving all player rolls (let's say 10 people rolled)
5) RollAddOn checks if players that rolled are in your guild (+10 [i]ifs)[/i]
6) Done.

For this case, you did 50 ifs.

In the end, the worst case scenario is 80 ifs per boss kill (i.e. you are in a 40man raid and everyone rolled). Way better than your first solution: 2000 ifs and your other solution 200 ifs.


For further information, I recommend using GetTime() to see how much time these 3 solutions take to do the job.
AfterAfterlife
Grunt
Grunt
 

Re: [LUA Question] sort key based table by value

by Renew » Mon Apr 04, 2016 12:56 pm

AfterAfterlife wrote:
Renew wrote:this doesnt work - the DKP values are stored in the guild notes...and they can change each boss :)

If it's an addOn that updates the DKP after each boss kill, then the solution here is to update your guildTable as well. You don't need to update all your guildTable (i.e. check offline players), instead you just update your raid members that are guild members too.


its a standalone addon (everyone in the guild can use it, you dont have to be the raidleader or the player with the DKP addon).
i have to call GetGuildRosterInfo each bosskill for the whole guild - there is no workarround for that, i think a IF state is faster then store the guild infos and loop it through all rollers
my Addons:
- Vanilla Healing Assignments - /viewtopic.php?f=63&t=23326
- Vanilla Storyline -
User avatar
Renew
Senior Sergeant
Senior Sergeant
 


Return to Addons & macros