+ Reply to Thread
Results 1 to 11 of 11

Thread: [Addon] Super Meter - Need help with table.sort

  1. #1
    Rift Chaser Ferather's Avatar
    Join Date
    Jun 2011
    Posts
    341

    Default [Addon] Super Meter - Need help with table.sort

    Hi again,

    Recently decided to give Super Meter a total re-coding, And are stuck with the table.sort function

    I have 3 tables all aligned together to make table.concat into 3 frames easy, However I am having trouble with the table.sort, As far as I can tell I cant seem to sort all 3 tables accordingly.

    The tables in written form look like this:

    Table1: Table2: Table3:
    Name Mode1 Mode2

    e.g.

    Ferather 1000 1000
    Ferather2 1356 800
    Ferather3 24 0

    I would like to sort all 3 tables for each mode I am in e.g. DPS

    Code:
    Code:
    function SuperMeter:Sort()
    	local encounter = encounter()
    	local mode = SuperMeter_mode
    	local mode1 = SuperMeter_mode1
    	local mode2 = SuperMeter_mode2
    
    	local Mode1 = 0
    	local Mode2 = 0
    	local mode1Text = ""
    	local mode2Text = ""
    	local nameText = ""
    	local sortMode = ""
    
    	if SuperMeter_inCombat then
    		encounter.allies.name = {}
    		encounter.allies.mode1 = {}
    		encounter.allies.mode2 = {}
    		encounter.enemies.name = {}
    		encounter.enemies.mode1 = {}
    		encounter.enemies.mode2 = {}
    	end
    
    	for k,v in pairs (encounter.units) do
    		local unit = encounter.units[k]
    		local mode = SuperMeter_mode
    		local now = Inspect.Time.Frame()
    		local time = now - encounter.startCombat
    		
    		if not SuperMeter_inCombat then
    			time = encounter.combatTime - encounter.startCombat
    		end
    		
    		if mode1 == "DPS" then
    			Mode1 = unit.damage / time
    		elseif mode2 == "DPS" then
    			Mode2 = unit.damage / time
    		end
    		if mode1 == "DMG" then
    			Mode1 = unit.damage
    		elseif mode2 == "DMG" then
    			Mode2 = unit.damage
    		end
    		if mode1 == "HPS" then
    			Mode1 = unit.healing / time
    		elseif mode2 == "HPS" then
    			Mode2 = unit.healing / time
    		end
    		if mode1 == "HLG" then
    			Mode1 = unit.healing
    		elseif mode2 == "HLG" then
    			Mode2 = unit.healing
    		end
    		if mode1 == "OPS" then
    			Mode1 = unit.overHealing / time
    		elseif mode2 == "OPS" then
    			Mode2 = unit.overHealing / time
    		end
    		if mode1 == "OHG" then
    			Mode1 = unit.overHealing
    		elseif mode2 == "OHG" then
    			Mode2 = unit.overHealing
    		end
    		if mode1 == "OKL" then
    			Mode1 = unit.overKill
    		elseif mode2 == "OKL" then
    			Mode2 = unit.overKill
    		end
    		if mode1 == "DTN" then
    			Mode1 = unit.damageTaken
    		elseif mode2 == "DTN" then
    			Mode2 = unit.damageTaken
    		end
    		if mode1 == "HTN" then
    			Mode1 = unit.healingTaken
    		elseif mode2 == "HTN" then
    			Mode2 = unit.healingTaken
    		end
    		if mode1 == "ASB" then
    			Mode1 = unit.damageAbsorbed
    		elseif mode2 == "ASB" then
    			Mode2 = unit.damageAbsorbed
    		end
    		if mode1 == "AVD" then
    			Mode1 = unit.damageAvoided
    		elseif mode2 == "AVD" then
    			Mode2 = unit.damageAvoided
    		end
    		if mode1 == "BLK" then
    			Mode1 = unit.damageBlocked
    		elseif mode2 == "BLK" then
    			Mode2 = unit.damageBlocked
    		end
    		if mode1 == "DFT" then
    			Mode1 = unit.damageDeflected
    		elseif mode2 == "DFT" then
    			Mode2 = unit.damageDeflected
    		end
    		if mode1 == "MSD" then
    			Mode1 = unit.damageMissed
    		elseif mode2 == "MSD" then
    			Mode2 = unit.damageMissed
    		end
    		
    		if SuperMeter_inCombat then
    			if encounter.units[k].relation == "friendly" then
    				table.insert(encounter.allies.name, encounter.units[k].name)
    				table.insert(encounter.allies.mode1, string.format("%4.0d", Mode1))
    				table.insert(encounter.allies.mode2, string.format("%4.0d", Mode2))
    			else
    				table.insert(encounter.enemies.name, encounter.units[k].name)
    				table.insert(encounter.enemies.mode1, string.format("%4.0d", Mode1))
    				table.insert(encounter.enemies.mode2, string.format("%4.0d", Mode2))
    			end
    		end
    		
    		if SuperMeter_side == "allies" then
    			sortMode = encounter.allies
    			nameText = table.concat(encounter.allies.name,"\n")
    			mode1Text = table.concat(encounter.allies.mode1,"\n")
    			mode2Text = table.concat(encounter.allies.mode2,"\n")
    		else
    			sortMode = encounter.enemies
    			nameText = table.concat(encounter.enemies.name,"\n")
    			mode1Text = table.concat(encounter.enemies.mode1,"\n")
    			mode2Text = table.concat(encounter.enemies.mode2,"\n")
    		end
    		
    		if mode == "DPS" or mode == "DMG" then
    			--- Table.sort goes here and for each mode
    		elseif mode == "HPS" or mode == "HLG" then
    			
    		elseif mode == "OPS" or mode == "OHG" then
    			
    		elseif mode == "OKL" then
    			
    		elseif mode == "DTN" then
    			
    		elseif mode == "HTN" then
    			
    		elseif mode == "ASB" then
    			
    		elseif mode == "AVD" then
    			
    		elseif mode == "BLK" then
    			
    		elseif mode == "DFT" then
    			
    		elseif mode == "MSD" then
    		
    		end
    	end
    	SuperMeter.UI.Interface:CombatText(nameText, mode1Text, mode2Text)
    end

  2. #2
    RIFT Guide Writer Noshei's Avatar
    Join Date
    Feb 2011
    Posts
    1,886

    Default

    So table.sort is best used with a function that tells it how to sort. Here is what I use in EasyMail to get A-Z sorting.

    table.sort(EM.Contacts.List.Friends, function(a,b) return a<b end)

    if you want you can reverse that to get Z-A sorting.

  3. #3
    Plane Walker Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    439

    Default

    Quote Originally Posted by Noshei View Post
    table.sort(EM.Contacts.List.Friends, function(a,b) return a<b end)
    That's what table.sort does by default if not provided a sort method.
    People should read the Lua reference manual more often

    Ferather could you please simplify and shorten your example and post only the relevant code parts?
    I'm not really sure I understand what you are attempting to do.
    Author of the Imhothar's Bags addon.

  4. #4
    Shield of Telara Adelea's Avatar
    Join Date
    Mar 2011
    Posts
    734

    Default

    As Imho says its unclear what you are trying to do - sort needs something to sort on, and you havent explained how you want things sorted.

    You can also insert tables into your table-to-be-sorted, which may possibly make life easier.

    Code:
    SORTME = {}
    
    table.insert(SORTME, {name="Name1", mode1="ValM1.1", mode2="ValM2.1"})
    table.insert(SORTME, {name="Name2", mode1="ValM1.2", mode2="ValM2.2"})
    table.insert(SORTME, {name="Name3", mode1="ValM1.3", mode2="ValM2.3"})
    Then you can sort easily on any key:

    Code:
    --Sort on name
    table.sort(SORTME, function(a,b) return a.name < b.name end)
    Then iterate over the sorted SORTME and do what you need to do for each entry.

  5. #5
    Rift Chaser Ferather's Avatar
    Join Date
    Jun 2011
    Posts
    341

    Default Sorry still confused

    Sorry still confused, Still learning LUA.

    Here's a copy of my current version im working on.

    http://www.wikiupload.com/8I2NPIW8PNIT7RD

    In Function: function SuperMeter:Sort()

    lines 1139 : 1266

    Its the mode sort for DPS, HPS etc

    The master mode which is the left or right column, needs to sort the table that is being concentrated.

    Tables section is lines 770 : 791
    Last edited by Ferather; 10-17-2012 at 02:50 PM.

  6. #6
    Sword of Telara DoomSprout's Avatar
    Join Date
    Apr 2011
    Posts
    876

    Default

    EDIT: just reread Adelea's post above, and he's saying the same thing I am, so this post is kinda redundant. I'll leave it here in case an alternate explanation helps with understanding though.

    I'm finding it a little difficult to understand the code, probably because I don't know anything about SuperMeter. From a very quick look, it appears you have the following:

    (A) An array (numerically indexed table) containing names
    (B) An array containing values for mode 1
    (C) An array containing values for mode 2

    So you can find the name and two values for row number 3 no problem...

    However, if you were to sort table (B), so that row 3 becomes row 7, you've lost the link between this row and the same row in the other two tables (they are still row 3).

    I may be totally misreading the code, in which case, ignore me

    If I'm not though, you need to keep the name and the two data values together so that they can be sorted together as a single item.

    Therefore, you're probably looking at an array containing a 3 element table:

    local mydata =
    {
    { name = "Name01", mode1 = 10, mode2 = 20 },
    { name = "Name02", mode1 = 12, mode2 = 15 },
    { name = "Name03", mode1 = 7, mode2 = 40 },
    }

    Once you have the data structured like this, you could sort it using a call something like:

    Code:
    table.sort(mydata, function(a,b) return a.mode1 < b.mode1 end)
    Sorry if this isn't the problem - I just don't have time to read and understand the whole of SuperMeter's code
    Last edited by DoomSprout; 10-18-2012 at 04:35 AM.

    Gadgets: Unit Frames and Other Stuff for RIFT

  7. #7
    Rift Chaser Ferather's Avatar
    Join Date
    Jun 2011
    Posts
    341

    Default

    unfortunately none of this works as I need a table.concat to output the information as a list form into a frame line by line.

    how can I have a table.sort and keep the table.concat?

    Ive tried doing the sort as mentioned above, but they are returned as strings, I then tried inserting the data from the sorted table as a list into another table but then it gets unsorted :S
    Last edited by Ferather; 10-19-2012 at 06:50 AM.

  8. #8
    Sword of Telara DoomSprout's Avatar
    Join Date
    Apr 2011
    Posts
    876

    Default

    Quote Originally Posted by Ferather View Post
    unfortunately none of this works as I need a table.concat to output the information as a list form into a frame line by line.

    how can I have a table.sort and keep the table.concat?

    Ive tried doing the sort as mentioned above, but they are returned as strings, I then tried inserting the data from the sorted table as a list into another table but then it gets unsorted :S
    Assuming it's this bit of code you're talking about:

    Code:
    nameText = table.concat(encounter.allies.name,"\n")
    mode1Text = table.concat(encounter.allies.mode1,"\n")
    mode2Text = table.concat(encounter.allies.mode2,"\n")
    You could use the table of tables above, and do your own concatenation. Something along the lines of:

    Code:
    local nameText = ""
    local mode1Text = ""
    local mode2Text = ""
    for idx,row in ipairs(mydata) do
        nameText = nameText .. row.name .. "\n"
        mode1Text = mode1Text .. row.mode1 .. "\n"
        mode2Text = mode2Text .. row.mode2 .. "\n"
    end
    You may end up with a trailing "\n" when compared to table.concat(), but that's easy enough to deal with.

    Gadgets: Unit Frames and Other Stuff for RIFT

  9. #9
    Plane Walker Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    439

    Default

    Depending on the size of the strings the manual concatenation might work, but the larger the strings get the slower it is because every .. operator creates a new temporary string in memory. That's one of the reasons table.concat was introduced as it can do all the concatenations on one large output string.

    A little trick is to "misuse" string subsitution: (based on Adeleas example)
    Code:
    local separator = "\n"
    local pattern = string.rep("\000" .. separator, #SORTME - 1) .. "\000"
    
    local i = 0
    local nameText = string.gsub(pattern, "\000", function() i = i + 1 return SORTME[i].name end)
    i = 0
    local mode1Text = string.gsub(pattern, "\000", function() i = i + 1 return SORTME[i].mode1 end)
    i = 0
    local mode2Text = string.gsub(pattern, "\000", function() i = i + 1 return SORTME[i].mode2 end)
    Whether you use DoomSprouts solution or this really depends on the size of the strings you are dealing with. This solution has much less pressure on the garbage collector and creates much less temporary "garbage" strings. this solution works only if the size of SORTME is >= 1.

    Here I am using the null-character (\000) as subsitution character because it is extremely unlikely it appears as part of separator, which would cause too many substitutions and a "attempting to index a nil value" error.

    P.S.: A a note to the C-minded people: Lua is 8-bit transparent and does not rely on the null-terminator, so the example works as expected
    Author of the Imhothar's Bags addon.

  10. #10
    Sword of Telara DoomSprout's Avatar
    Join Date
    Apr 2011
    Posts
    876

    Default

    Quote Originally Posted by Imhothar View Post
    Depending on the size of the strings the manual concatenation might work, but the larger the strings get the slower it is because every .. operator creates a new temporary string in memory. That's one of the reasons table.concat was introduced as it can do all the concatenations on one large output string....
    Wow... took me about 5 reads of that code before I worked out what you're doing. Very clever

    Gadgets: Unit Frames and Other Stuff for RIFT

  11. #11
    Rift Chaser Ferather's Avatar
    Join Date
    Jun 2011
    Posts
    341

    Default

    Thanx guys works now

+ Reply to Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts