Thread Tools Display Modes
11-30-10, 10:12 AM   #1
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
Table Structure

Hello all.

Looking for some thoughts about table structure. I'm making an AtlasLoot-type addon which obviously has tables upon tables with items.

At the moment, the structure of a module-table look like this (for example):

lua Code:
  1. local t = {
  2.     ["Throne of the Tides"] = {
  3.         ["Order"] = "Lady Naz'jar:Commander Ulthok:Mindbender Ghur'sha:Ozumat:Trash",
  4.         ["Lady Naz'jar"] = {
  5.             ["Order"] = "Normal:Heroic",
  6.             ["Normal"] = "55202,55198,55195,55201,55203",
  7.             ["Heroic"] = "56267,56269,56268,56270,56266",
  8.         },
  9.         ...
  10.     ],
  11. }

(I know it's not localized etc, but not worrying about that right now.)

I use the field Order to make sure stuff is ordered properly since you can't trust the table (when used as a dictionary) to have the same structure. I guess my question is, is this a inefficient way to do it? When retrieving the data I do for match in string.gmatch(table.Order, "[^:]+") do.

Would a structure like this be more efficient/memory-friendly?

lua Code:
  1. local t = {
  2.     ["Throne of the Tides"] = {
  3.         [1] = {
  4.             label = "Lady Naz'jar",
  5.             data = {
  6.                 [1] = {
  7.                     label = "Normal",
  8.                     items = "55202,55198,55195,55201,55203",
  9.                 },
  10.                 [2] = {
  11.                     label = "Heroic",
  12.                     items = "56267,56269,56268,56270,56266",
  13.                 },
  14.             },
  15.         },
  16.     },
  17. }

Guessing this might be less efficient perhaps, due to it containing more nested tables. I suppose I could embed the label in the item-string as well and just getting that one out when "unpacking" stuff. Something like [1] = "Normal:55202,55198,55195,55201,55203".

Or is either of these ways completely bonkers? It's hard to draw any conclusions by looking at how much memory the addon uses in total, if it's "too much" or not.

Thankful for any input.
__________________
Oh, the simulated horror!
  Reply With Quote
11-30-10, 10:29 AM   #2
Xubera
A Cobalt Mageweaver
 
Xubera's Avatar
AddOn Author - Click to view addons
Join Date: May 2009
Posts: 207
I was under the impression that one style wouldnt really matter as long as you werent creating garbage, like endlessly creating new tables each time. If they are static they are holding memory, not causing cpu cycles (which is what would hender performance, i think...)

I would use the 2nd method myself, as everytime someone called it, it would take less commands such as :gmatch(), therefore using less cycles when the tables are active.

Though take my words like a pound of salt (not a grain) as I have not taken the time to research or claim that I know what really goes on in there. These are just the ideas that come to mind when I think of it
__________________
Chat Consolidate is the solution to any out of control trade chat. Ignore lines, throttle chat, consolidate posts!Follow the link to find out how!

▲ ▲ WoWInterface wont let me triforce >.>
  Reply With Quote
11-30-10, 11:12 AM   #3
Rilgamon
Premium Member
 
Rilgamon's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 822
I'd look at the ways you want to access the data.
Then construct it so that you can get to the data you need with as few
lookups as possible.
__________________
The cataclysm broke the world ... and the pandas could not fix it!
  Reply With Quote
11-30-10, 12:33 PM   #4
yssaril
A Warpwood Thunder Caller
 
yssaril's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2007
Posts: 96
The first is more efficient. lua is very efficient in loading/creating long strings but is slow when parsing tables at load time so you want to reduce the number of tables initially. With a bit of code you can then expand your strings into tables at runtime ondemand where the table creation time is minimal since you only create what you need right then and there
  Reply With Quote
11-30-10, 01:10 PM   #5
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
I see.

Taking what Rilgamon said into account, the 2nd alternative (albeit slightly tweaked) feels more manageable from an upkeep-perspective. Since I'll do more than just drops from mobs (stuff like factions and tiers) the number of sublabels ("Normal"/"Heroic" in the example above) can vary.

So right now, I'm thinking of doing like this:

lua Code:
  1. local t = {
  2.     ["Throne of the Tides"] = {
  3.         [1] = {
  4.             label = "Lady Naz'jar",
  5.             data = {
  6.                 [1] = "Normal:55202,55198,55195,55201,55203"
  7.                 [2] = "Heroic:56267,56269,56268,56270,56266",
  8.             },
  9.         },
  10.         ...
  11.     },
  12. }

I suppose I could cram all labels and items into just the one string but that feels like a maintenance-nightmare. :P The upside by doing this way rather than example 1 is that should be easier to localize as well as not having everything fail if the string in table.Order doesn't match the key used later.

The way it is used is basically this:
I register the table t with a name, this is then added to a list of Categories. So the example above would be added as "Dungeons" or similar. The next level contains the name of the dungeon(s), which is sorted alphabetically and then used as sub-Categories to the main Category. The next level is the key for the items and are added as a sub-list to a sub-Category (sorted by index, since bosses are in a specific order usually).

All this gets put into 3 dropdowns, dependent on each other. When an item is clicked in the sub-list dropdown, a page with the items appear where the data-label (Normal/Heroic) is a header and the items following are anchored to this label.
__________________
Oh, the simulated horror!
  Reply With Quote
12-01-10, 05:36 AM   #6
Xinhuan
A Chromatic Dragonspawn
 
Xinhuan's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 174
If you really want to be more efficient and use less memory, then you want to split your data into 2 or more separate tables.

That is if you have a structure that is

Code:
local t = {
  [1] = {label="abc", data="def"},
  [2] = {label="abcd", data="defg"},
  [3] = {label="abcde", data="defgh"},
}
Consider this instead:

Code:
local labels = {
  [1] = "abc",
  [2] = "abcd",
  [3] = "abcde",
}
local data = {
  [1] = "def",
  [2] = "defg",
  [3] = "defgh",
}
Not only do you have less tables, your code will often be faster as you don't have to access tables inside tables inside tables. The downside is that using this method of data storage will make sorting the data across the multiple tables more difficult and a custom sort function will be needed.

If the data is also manually compiled by hand, you will also have to make sure the data is synced across the multiple tables.
__________________
Author of Postal, Omen3, GemHelper, BankItems, WoWEquip, GatherMate, GatherMate2, Routes and Cartographer_Routes
  Reply With Quote
12-01-10, 05:54 AM   #7
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
Interesting. The data is manually gathered so using a structure like that feel like it would make maintenance more tedious, even if it's the most efficient. I'm not -that- worried about memory and stuff, at least not yet. With about half the items added and the browser more or less done, it still only uses roughly 80kb of memory (with all item-tables loaded directly and not only when used). I guess I just needed a sanity-check and some insights to good practices.

Thanks for all replies.
__________________
Oh, the simulated horror!
  Reply With Quote
12-02-10, 03:09 PM   #8
Xinhuan
A Chromatic Dragonspawn
 
Xinhuan's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 174
Well, a table access is magnitudes more expensive than assignment or if-then-else statements.

Also, every new empty table is about 80 bytes of memory. While memory isn't the biggest concern, if you have A LOT of data, you should consider rearranging the data into separate tables. It will make your code maintenance easier (because your code will be easier to read without tables in tables) even if your data maintenance becomes harder.
__________________
Author of Postal, Omen3, GemHelper, BankItems, WoWEquip, GatherMate, GatherMate2, Routes and Cartographer_Routes
  Reply With Quote
12-02-10, 06:45 PM   #9
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
I understand that looking up a single level table is faster. But I don't have that much data, nor do I intend to, I'll basically just have Cataclysm stuff in it. I've reworked everything to the concept I outlined a few posts back, but gonna think about what you said regarding separating it into different tables. Just need a "clever" way to assemble it all together I guess.

In the long run I realize that the gain probably is so small (due to size of the data) that it doesn't make any sense to worry too much about it. But it's interesting never the less, really appreciate the feedback. Right now I'm mostly thinking of caching the item-strings so that if I choose to display those items again I can bypass the whole string.(g)match thingamajig. But in all probability I'm over-complicating it in relation to the size.

At the moment I have all the data I'm going to need (bar patches) for 5-man dungeons, reputations and Justice/Valor items (excluding tiers) and at load it's about 67kb with the browser (which I could probably clean up quite a bit). It's barely a drop in the ocean.

On a sort of related note, there's not really any point in assigning upvalues for variables used in for-loops is there? I think I've read somewhere that they get recycled instantly after the loop or something anyway.
__________________
Oh, the simulated horror!
  Reply With Quote
12-03-10, 12:42 AM   #10
Xubera
A Cobalt Mageweaver
 
Xubera's Avatar
AddOn Author - Click to view addons
Join Date: May 2009
Posts: 207
In the long run I realize that the gain probably is so small (due to size of the data) that it doesn't make any sense to worry too much about it. But it's interesting never the less, really appreciate the feedback.
A single grain of rice can tip the scale. One man may be the difference between victory and defeat.

If everyone made all their addons with no regard, then it may not make a difference when its only their running, but get enough running together and the garbage collector gets busy.

In all seriousness though, I don't know much about optimization or memory efficient methods, so I won't give advice I cant give. But you don't have to mention you plan on not caring about sloppy code in every post.

Still interested if what comes from this project of yours Like a building list of items, that continues to grow!
__________________
Chat Consolidate is the solution to any out of control trade chat. Ignore lines, throttle chat, consolidate posts!Follow the link to find out how!

▲ ▲ WoWInterface wont let me triforce >.>
  Reply With Quote
12-03-10, 01:16 AM   #11
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,322
Originally Posted by Ailae View Post
lua Code:
  1. local t = {
  2.     ["Throne of the Tides"] = {
  3.         ["Order"] = "Lady Naz'jar:Commander Ulthok:Mindbender Ghur'sha:Ozumat:Trash",
  4.         ["Lady Naz'jar"] = {
  5.             ["Order"] = "Normal:Heroic",
  6.             ["Normal"] = "55202,55198,55195,55201,55203",
  7.             ["Heroic"] = "56267,56269,56268,56270,56266",
  8.         },
  9.         ...
  10.     ],
  11. }
It's usually a good idea to structure your data in a way that's the easiest to access without using too much CPU power.
I would advise something like this.
lua Code:
  1. local t={
  2.     ["Throne of the Tides"]={
  3.         ["Normal"]={
  4. --          Order List
  5.             "Lady Naz'jar";
  6.             "Commander Ulthok";
  7.             "Mindbender Ghur'sha";
  8.             "Ozumat";
  9.             "Trash";
  10.  
  11.             ["Lady Naz'jar"]={55202,55198,55195,55201,55203};
  12.             ["Commander Ulthok"]={};
  13.             ["Mindbender Ghur'sha"]={};
  14.             ["Ozumat"]={};
  15.             ["Trash"]={};
  16.         };
  17.         ["Heroic"]={
  18. --          Order List
  19.             "Lady Naz'jar";
  20.             "Commander Ulthok";
  21.             "Mindbender Ghur'sha";
  22.             "Ozumat";
  23.             "Trash";
  24.  
  25.             ["Lady Naz'jar"]={56267,56269,56268,56270,56266};
  26.             ["Commander Ulthok"]={};
  27.             ["Mindbender Ghur'sha"]={};
  28.             ["Ozumat"]={};
  29.             ["Trash"]={};
  30.         };
  31.     };
  32.     ...
  33. };
The order lists will get incremental numerical indicies and can be used in a for loop using ipairs(). The item table can then be accessed using the value as the table's index.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
12-03-10, 06:03 AM   #12
Xinhuan
A Chromatic Dragonspawn
 
Xinhuan's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 174
Don't use ipairs().

It is proven slower in every case compared to
Code:
for k = 1, #t do
    local v = t[k]
    -- Do stuff with k and v
end
because ipairs() is a function call, and every iteration calls an iterator function that is returned by ipairs() to increment the counter. So for a table of 200 in size, that's 201 unnecessary function calls.
__________________
Author of Postal, Omen3, GemHelper, BankItems, WoWEquip, GatherMate, GatherMate2, Routes and Cartographer_Routes
  Reply With Quote
12-03-10, 07:39 AM   #13
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
Originally Posted by Xubera View Post
A single grain of rice can tip the scale. One man may be the difference between victory and defeat.

If everyone made all their addons with no regard, then it may not make a difference when its only their running, but get enough running together and the garbage collector gets busy.

In all seriousness though, I don't know much about optimization or memory efficient methods, so I won't give advice I cant give. But you don't have to mention you plan on not caring about sloppy code in every post.

Still interested if what comes from this project of yours Like a building list of items, that continues to grow!
I think you misunderstood me if you think I don't care about sloppy code. All I meant was that the difference would probably be negligible for this amount of data, so I can sacrifice some efficiency for more easily (to me) managed code. If I really didn't care I wouldn't be here asking questions, would I? I do this for fun in my spare time, but I try to do the best I can. I tried searching for any previous discussions on the topic but couldn't find anything substantial.

If you want to you can look at it here:
https://github.com/ailae/Shinies

But I guess it's more or less quite the mess still. Was my first try with dropdowns and scrolls and whatnot. But it works! :P
__________________
Oh, the simulated horror!
  Reply With Quote
12-03-10, 07:56 AM   #14
Xubera
A Cobalt Mageweaver
 
Xubera's Avatar
AddOn Author - Click to view addons
Join Date: May 2009
Posts: 207
oi oi, i hate the drop down menus too ><
__________________
Chat Consolidate is the solution to any out of control trade chat. Ignore lines, throttle chat, consolidate posts!Follow the link to find out how!

▲ ▲ WoWInterface wont let me triforce >.>
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Table Structure

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