Thread Tools Display Modes
07-16-14, 07:27 AM   #1
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Table Sorting

Is is possible to return this table names sorted?

local categories = {
["Achievements"] = { },
["Action Bars"] = { },
["Arena"] = { },
["Bags"] = { },
["Bank and VoidStorage"] = { },
["Battlegrounds and PvP"] = { },
["Bottom Bar"] = { },
["Boss Specific"] = { },
["Class Specific"] = { },
["Dungeons and Raids"] = { },
["Game Menu"] = { },
["Guild"] = { },
["Info Panels"] = { },
["Loot"] = { },
["Map"] = { },
["Minimap"] = { },
["Miscellaneous"] = { },
["Unit: Focus"] = { },
["Unit: Party"] = { },
["Unit: Pet"] = { },
["Unit: Player"] = { },
["Unit: Target"] = { },
["Vehicle"] = { },
["Pet Battle"] = { },
}
  Reply With Quote
07-16-14, 07:53 AM   #2
Malakahh
An Aku'mai Servant
AddOn Author - Click to view addons
Join Date: Jun 2009
Posts: 30
Tables in lua are key-value pairs and as such have no particular order, as with an index-based array. You should instead aim to iterate through it in some order to mimic what you wish to achieve.

This should point you in the right direction:
http://stackoverflow.com/questions/1...a-table-in-lua
  Reply With Quote
07-16-14, 08:00 AM   #3
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Malakahh View Post
Tables in lua are key-value pairs and as such have no particular order, as with an index-based array. You should instead aim to iterate through it in some order to mimic what you wish to achieve.

This should point you in the right direction:
http://stackoverflow.com/questions/1...a-table-in-lua
Thanks, actually that spairs is awesome. Thats what i need.
  Reply With Quote
07-16-14, 12:09 PM   #4
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
Originally Posted by Resike View Post
Thanks, actually that spairs is awesome. Thats what i need.
It's also wasteful if used often: It's creating a new table AND anonymous function every time it's called. I typically just copy the keys from the dictionary-style table to an index-style table and sort on that using a function that I declare/define exactly once. That's essentially what this spairs function is doing, but without creating needless garbage.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
07-16-14, 01:28 PM   #5
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Torhal View Post
It's also wasteful if used often: It's creating a new table AND anonymous function every time it's called. I typically just copy the keys from the dictionary-style table to an index-style table and sort on that using a function that I declare/define exactly once. That's essentially what this spairs function is doing, but without creating needless garbage.
Hmm yeah, but if you only use it once on load, than it shouldn't eat up that much more resources, then a simple table.sort or ipairs. However if you update your table and resort it multiple times, then you shouln't use this.

Last edited by Resike : 07-16-14 at 01:33 PM.
  Reply With Quote
07-16-14, 11:59 PM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
I'm assuming you just want to display the categories in (for example) alphabetical order, and also assuming that the list of categories is static, in which case I'd just do this:

Code:
local categories = {
     ["Achievements"] = { },
     ["Action Bars"] = { },
     ["Arena"] = { },
     ["Bags"] = { },
     ["Bank and VoidStorage"] = { },
     -- etc.
}

local categoryOrder = { }
for k in pairs(categories) do
    tinsert(categoryOrder, k)
end
table.sort(categoryOrder)
Then when you display them:

Code:
for i = 1, #categoryOrder do
     local categoryName = categoryOrder[i]
     local categoryData = categories[categoryName]
     -- do stuff here
end
I think this is what Torhal was describing. If you're just sorting once, there's absolutely no need to define and call a specialized function -- as a general rule, if you're only going to run some code once, just run it in place, rather than wrapping it in a separate function elsewhere and calling that function. A common exemption would be definining a large AceOptions table at login, and wanting to do that in a separate file from your main addon logic -- it would be totally fine to have a "LoadOptions" function in another file, that's only called once at login. However, for something as simple as creating a sorted list of table keys, that's only ~5 lines of code, wrapping that up in a generalized function just wastes resources (however small) and adds unnecessary complexity to your code.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-17-14, 04:48 AM   #7
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
I see. Now my issue is that under the subtables i would like to keep the order as i constructed the table:

["Unit: Player"] = {
["PlayerFrame"] = {
[1] = "TopLeft",
[2] = "UIParent",
[3] = "TopLeft",
[4] = 19,
[5] = -4,
},
["PlayerPVPIcon"] = {
[1] = "TopLeft",
[2] = "PlayerFrame",
[3] = "TopLeft",
[4] = 18,
[5] = -20,
},
},

Is it possbile somehow, or i really have to use number indexed tables? I just really would like to avoid using 5 embedded for cycles.

Last edited by Resike : 07-17-14 at 05:01 AM.
  Reply With Quote
07-17-14, 09:51 AM   #8
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Not sure what you mean exactly, but only the first level of keys will get sorted using the logic provided in this thread.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
07-17-14, 10:46 AM   #9
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Just use the code I posted. It does not affect the original table at all. It merely creates a second table containing a sorted list of the keys from the first table. To iterate over the keys in Table #1 in order, you actually iterate over the sorted values in Table #2, and then get their values as keys in Table #1. It doesn't matter what you fill the sub-tables in Table #1 with, or whether you add/remove/change stuff in there throughout the session. If you add/remove top-level keys in Table #1 (eg. category names) then just wipe, re-fill, and re-sort Table #2.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-17-14, 11:20 AM   #10
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Inside my sorted table, i want to store more string indexed tables, however i don't want to sort this table alphabetically, and i don't want it to reach randomly like the pairs(), i want it sorted the way i created the table, just like in the indexed tables, but with string keys:

local table = {
["zoo"] = { }, -- 1
["katz"] = { }, -- 2
["hedgehog"] = { } -- 3
}
  Reply With Quote
07-17-14, 11:50 AM   #11
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Originally Posted by Resike View Post
Inside my sorted table, i want to store more string indexed tables, however i don't want to sort this table alphabetically, and i don't want it to reach randomly like the pairs(), i want it sorted the way i created the table, just like in the indexed tables, but with string keys:

local table = {
["zoo"] = { }, -- 1
["katz"] = { }, -- 2
["hedgehog"] = { } -- 3
}
That is not possible with a hash table.
  Reply With Quote
07-17-14, 12:17 PM   #12
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
As Dridzt said, you can't do that. That's the whole point of the code I posted. You bypass this "problem" by having one table that stores key/value pairs, and a second table that stores a sorted list of the keys from the first table. It's neither possible nor necessary to sort the keys in a table in Lua. The only sorting that's possible is on the values of an indexed table.

If you think that what I posted will not work for what you're trying to do, please explain more clearly what you're trying to do.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 07-17-14 at 12:21 PM.
  Reply With Quote
07-17-14, 03:23 PM   #13
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Phanx View Post
As Dridzt said, you can't do that. That's the whole point of the code I posted. You bypass this "problem" by having one table that stores key/value pairs, and a second table that stores a sorted list of the keys from the first table. It's neither possible nor necessary to sort the keys in a table in Lua. The only sorting that's possible is on the values of an indexed table.

If you think that what I posted will not work for what you're trying to do, please explain more clearly what you're trying to do.
I understand that i just wanted to dodge to use the indexed method.

My table looks like this, and i want to reach each table easily, and since the table is gonna be really big i rather not keep more helper tables for it:

Lua Code:
  1. local catz = {
  2.     -- Sorted table
  3.     [...],
  4.     ["Unit: Player"] = {
  5.         -- Sort this like how you add the values
  6.         [...],
  7.         ["PlayerFrame"] = {
  8.             -- Well this is sorted
  9.             [1] = "TopLeft",
  10.             [2] = "UIParent",
  11.             [3] = "TopLeft",
  12.             [4] = 19,
  13.             [5] = -4,
  14.         },
  15.         ["PlayerPVPIcon"] = {
  16.             [1] = "TopLeft",
  17.             [2] = "PlayerFrame",
  18.             [3] = "TopLeft",
  19.             [4] = 18,
  20.             [5] = -20,
  21.         },
  22.         [...],
  23.     },
  24.     ["Unit: Target"] = {
  25.         [...],
  26.         ["TargetFrame"] = {
  27.             [1] = "TopLeft",
  28.             [2] = "UIParent",
  29.             [3] = "TopLeft",
  30.             [4] = 250,
  31.             [5] = -4,
  32.         },
  33.         [...],
  34.     },
  35.     [...],
  36. }

The issue with the indexed method:

Lua Code:
  1. local cats = {
  2.     ["Unit: Player"] = {
  3.         [1] = {name = L["Player"], frame = "PlayerFrame", pos = {[1] = "TopLeft", [2] = "UIParent", [3] = "TopLeft", [4] = 19, [5] = -4,}},
  4.     },
  5. }

How the hell am I gonna reach easily the "pos" table, if i only know the frame's name?

Last edited by Resike : 07-17-14 at 03:31 PM.
  Reply With Quote
07-18-14, 04:51 PM   #14
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Resike View Post
I understand that i just wanted to dodge to use the indexed method.
Well, you can't. Asking how you can dodge the inability to sort keys in a hash table is like asking how you can dodge the error you'd get if you tried to print("cat" / 0) or print({} + true) -- you just can't do that, and that's just how it is. I don't really know how to explain it any more clearly.

Originally Posted by Resike View Post
The issue with the indexed method:

Lua Code:
  1. local cats = {
  2.     ["Unit: Player"] = {
  3.         [1] = {name = L["Player"], frame = "PlayerFrame", pos = {[1] = "TopLeft", [2] = "UIParent", [3] = "TopLeft", [4] = 19, [5] = -4,}},
  4.     },
  5. }
I don't think you understand what's going on in the code I posted, because the code I posted will not produce a result anything like that.

Originally Posted by Resike View Post
My table looks like this, and i want to reach each table easily, and since the table is gonna be really big i rather not keep more helper tables for it: ... How the hell am I gonna reach easily the "pos" table, if i only know the frame's name?
How do you reach the "pos" table right now? The code I posted would not affect your original table at all, nor any of its subtables. You could still do whatever you're currently doing with your original table. The only thing my code would do would give you an additional and optional way to loop over the table's top-level keys in alphabetical order. If you're doing anything other than iterating over the top-level key/value pairs -- eg. if you're looking up a specific deeper path in the table -- you would do it the same way you're doing it right now.

Also, some corrections to the comments in your example code:
Code:
local catz = {
	-- Sorted table
	-- NO! This table is NOT sorted! You CANNOT sort table keys in Lua!
	["Unit: Player"] = {
		-- Sort this like how you add the values
		-- NO! Keys are NOT sortable, period.
		["PlayerFrame"] = {
			-- Well this is sorted
			-- Yes, but that's beacuse this is an indexed table,
			-- not a hash table, and it's the VALUES that are sorted.
			[1] = "TopLeft",
			[2] = "UIParent",
			[3] = "TopLeft",
			[4] = 19,
			[5] = -4,
		},
	},
}
Maybe you should give a better description of what you actually want to do here. Why do you think you need to "sort the keys" in this table? Why do you need the key/value pairs in a particular order?
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-20-14, 03:48 PM   #15
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Phanx View Post
Well, you can't. Asking how you can dodge the inability to sort keys in a hash table is like asking how you can dodge the error you'd get if you tried to print("cat" / 0) or print({} + true) -- you just can't do that, and that's just how it is. I don't really know how to explain it any more clearly.
Well it's lua's dumb way to handle tables like this, i mean whats the advantage of reach/store a table totally randomly? In other languaes there are a solution for this, and since i don't know everything about lua thats why i asked it.

Originally Posted by Phanx View Post
How do you reach the "pos" table right now? The code I posted would not affect your original table at all, nor any of its subtables. You could still do whatever you're currently doing with your original table. The only thing my code would do would give you an additional and optional way to loop over the table's top-level keys in alphabetical order. If you're doing anything other than iterating over the top-level key/value pairs -- eg. if you're looking up a specific deeper path in the table -- you would do it the same way you're doing it right now.
Well with hashkeys i can simply reach the table i want with randomtable[frame:GetName()]. But i can't do this with the indexed way, since i don't know whats the table index the frame i looking for. Means that i'm gonna have to keep another table with the hasvalues, and thats the thing i really wanted to dodge.

Originally Posted by Phanx View Post
Also, some corrections to the comments in your example code:
Code:
local catz = {
	-- Sorted table
	-- NO! This table is NOT sorted! You CANNOT sort table keys in Lua!
	["Unit: Player"] = {
		-- Sort this like how you add the values
		-- NO! Keys are NOT sortable, period.
		["PlayerFrame"] = {
			-- Well this is sorted
			-- Yes, but that's beacuse this is an indexed table,
			-- not a hash table, and it's the VALUES that are sorted.
			[1] = "TopLeft",
			[2] = "UIParent",
			[3] = "TopLeft",
			[4] = 19,
			[5] = -4,
		},
	},
}
This is not an example code, this is how i would like my table to look in the ideal way, with no indexed values in the second level, so i could easily reach the 3rd indexed values.

Originally Posted by Phanx View Post
Maybe you should give a better description of what you actually want to do here. Why do you think you need to "sort the keys" in this table? Why do you need the key/value pairs in a particular order?
Because i want to keep the categoies in alphabetical order, however i want to keep the subcats in order of apperance : "Character Info", "SpellBookFrame", "PlayerTalentFrame", "AchievementFrame" and not sorted.
  Reply With Quote
07-20-14, 04:33 PM   #16
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
The only way to sort a hash table in any language is to store the order in a second index, how else would it know what order to iterate in.
  Reply With Quote
07-20-14, 05:27 PM   #17
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
No language I've ever worked with has any way of sorting a hash table either. The very definition of a hash table is that it's an "unordered associative array".

Originally Posted by Resike View Post
Because i want to keep the categoies in alphabetical order, however i want to keep the subcats in order of apperance : "Character Info", "SpellBookFrame", "PlayerTalentFrame", "AchievementFrame" and not sorted.
But why do you want to "keep" the categories in alphabetical order? Are you expecting to have them in alphabetical order in your saved variables file? (That's impossible, so just give up now.) Are you showing them in a list in a GUI to the addon user? (Just use the solution I posted, as it's the only solution possible; the helper function Malakahh posted earlier is just a more complicated variation on the same thing with a lot of unnecessary overhead.) Are you doing something else? If so, what is it?

I also really don't understand why you keep talking about the subcategories. The solution posted in this thread only addresses the issue of iterating over the top-level keys in alphabetical order and does not in any way affect the values of those keys, nor any keys in sub-tables. If you want to iterate over keys in sub-tables in a fixed order, you can do that too, but as with the alphabetical iteration, it will require either using a second, indexed table to hold the keys in the desired order, or changing your whole table structure to only use indexed tables.

I feel like you're focusing too hard on this specific method you've imagined, and forgetting about the actual problem you're trying to solve. Right now you're trying to put the square peg in the round hole, and you keep asking how to do that, rather than realizing that what you really need to do is just get the peg into the box, and then taking a step back and realizing that there is a round hole right next to the square hole, and you don't actually have to put the square peg through the round hole after all. But if you won't tell us what the real problem is, all we can do is keep trying to explain why the solution you want to use just isn't going to work.

I really want to help you here, but unless you can actually tell us what the general problem you're trying to solve is, I just don't think there's anything more I can add to this topic.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-21-14, 12:13 PM   #18
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
You must settle using 0..n indexing if you like the order to be sorted when you iterate it - without sorting the keys in a separate table and such. Phanx already said what there is to be said on this subject.
__________________
Profile: Curse | Wowhead
  Reply With Quote
02-01-15, 01:19 PM   #19
Sweetsour
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Dec 2014
Posts: 130
I figure I'd recycle this post with the issue I've run into.

It seems that when I try to sort one table, it's also sorting another table that I don't want sorted.

Lua Code:
  1. for k,v in pairs(RP_SavedVars['attendance']['players']) do
  2.     table.insert(playerNames,k);
  3. end
  4.  
  5. local tempTable = {};
  6. tempTable = playerNames; -- The reason for this is I need "playerNames" table to remain unsorted
  7.  
  8. --I check the tables before the sort
  9. for i=1,numPlayers do
  10.     ChatFrame3:AddMessage(tempTable[i].." | "..playerNames[i]);
  11. end
  12.  
  13. --Everything looks normal before the sort
  14. --[1] Zurom | Zurom
  15. --[2] Sweetsour | Sweetsour
  16. --[3] Thumpasaur | Thumpasaur
  17. --[4] Ezylryb | Ezylryb
  18. --[5] Ultimicia | Ultimicia
  19.  
  20. table.sort(tempTable);
  21.  
  22. --I check the tables after the sort
  23. for i=1,numPlayers do
  24.     ChatFrame3:AddMessage(tempTable[i].." | "..playerNames[i]);
  25. end
  26.  
  27. -- Now *BOTH* tables appear to have been sorted as:
  28. --[1] Ezylryb | Ezylryb
  29. --[2] Sweetsour | Sweetsour
  30. --[3] Thumpasaur | Thumpasaur
  31. --[4] Ultimicia | Ultimicia
  32. --[5] Zurom | Zurom

Any idea(s) as to why this may be happening?

Last edited by Sweetsour : 02-01-15 at 01:21 PM.
  Reply With Quote
02-01-15, 01:32 PM   #20
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Tables are reference values in Lua.

When you do table1 = table2 you don't get a copy of table2, you just get 2 names pointing to the same table.

You probably want tempTable = CopyTable(playerNames)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Table Sorting

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off