1. Post #1
    LaughingLeader's Avatar
    July 2011
    19 Posts
    I'm having a bit of trouble getting a table (in Tiramisu), filled with item data, to sort by it's category (in alphabetical order). I'm still fairly new to LUA and programming in general, so I'm not sure if I'm going about it the right way.

    The snippet that builds the business menu item data looks like this:


    CAKE.Business = {}
    --Copies all buyable items on the CAKE.Business table.
    function CAKE.BuildItemGroups()
    	local tbl = {}
    	for k,v in pairs(CAKE.ItemData) do
    		if !CAKE.Business[v.ItemGroup] then CAKE.Business[v.ItemGroup] = {} end
    		if v.Purchaseable then
    			tbl = {}
    			tbl.Class = v.Class
    			tbl.Model = v.Model
    			tbl.Name = v.Name
    			tbl.Description = v.Description .. "\nPrice: " .. v.Price
    			tbl.Price = v.Price
    			tbl.category = v.category
    			tbl.IconM = v.IconM
    			--Category Sort
    			table.sort(tbl, function(a,b) 
    				return a.category > b.category 
    			--Test the results
    			 for k,v in pairs(tbl) do 
    			 print(k, v) 
    			table.insert(CAKE.Business[v.ItemGroup], tbl)

    I've tried sorting the "tbl" table by category, and even the CAKE.Business menu by category, but both don't seem to sort when I do that. I haven't been getting any errors, but the item order doesn't go alphabetical. I've also double-checked to make sure the category key is working, and it is. It even shows up on the item tooltip via this:

    --Sets an item to be used on the inventory slot. The item thing is a table, not a string. Amount defaults to 1.
    function PANEL:SetItem( item, amount )
    	self.Item = item
    	if !self.Icon then
    		self.Icon = vgui.Create( "InventorySlot_Icon", self )
    		self:SetIconSize( self.IconSize )
    	-- Item tooltip. Added item.category.
    	if item.Description != "" then self:SetToolTip( "[" .. item.category .. "]" .. "\n" .. item.Name .. "\n" .. item.Description )
    	else self:SetToolTip( "[" .. item.category .. "]" .. "\n" .. item.Name ) end
    	-- Changes the Icon model to the "IconM" field if valid. 
    	if item.IconM == "" then self.Icon:SetModel( item.Model )
    	else self.Icon:SetModel( item.IconM ) end
    	self:SetAmount( amount or 1 )
    	self:OnUseItem( item, amount )

    The business menu actually builds the icons in this little snippet of code:

    local icontable = {}
    for k, item in pairs( BusinessTable[buygroup] ) do
    	icontable[k] = vgui.Create( "InventorySlot" )
    	icontable[k]:SetIconSize( 48 )
    	icontable[k]:SetItem( item )				
    	icontable[k].OnMousePressed = function()
    	icontable[k].OnMouseReleased = function() end
    	icontable[k].OpenMenu = function()
    		local ContextMenu = DermaMenu()
    		ContextMenu:AddOption("Buy", function() LocalPlayer():ConCommand("rp_buyitem " .. icontable[k]:GetItem().Class ) end)
    	icontable[k].PaintOver = function()
    		surface.SetTextPos( icontable[k]:GetWide() - 20, icontable[k]:GetTall() - 14);
    		surface.DrawText( icontable[k]:GetItem().Price or "0" )
    	grid:AddItem( icontable[k] )

    So, I'm not sure if I've been going about this the right way, but I figured that sorting the table in the business.lua file would work, as then the code pulls that data and builds everything else. It doesn't seem to be working though, as the print output to the console isn't in alphabetical order (by category). It'll show zipties as first (category: Miscellaneous), then an Alcohol item, then some Weaponry, followed by random mixtures of other items. Also, any changes to how the sorting function compares the a.category and b.category just shifts the items around in a weird way.

    Any ideas on how to get this to work would be appreciated.

  2. Post #2

    May 2009
    1,160 Posts

    Sorts through a table's keys from lowest to highest, starting with numbers.


    This goes by value of the key.


    This goes by member of a table. Syntax is SortedPairsByMemberValue(table,member)

  3. Post #3
    LaughingLeader's Avatar
    July 2011
    19 Posts
    Unfortunately, that's giving me an error:

    			for k, v in SortedPairsByMemberValue(tbl, "category") do
    			print(k, v.category)

     Hook 'TiramisuBuildItemGroups' Failed: [lua\includes\extensions\table.lua:478] attempt to index local 'v' (a string value)

    Here's the hook (it just calls the CAKE.BuildItemGroups() function I've been messing with):

    hook.Add( "InitPostEntity", "TiramisuBuildItemGroups", function() 

    Line 478 of table.lua is v.__key = k in this:

       Name: table.ClearKeys( table, bSaveKey )
       Desc: Clears the keys, converting to a numbered format
    function table.ClearKeys( Table, bSaveKey )
    	local OutTable = {}
    	for k, v in pairs( Table ) do
    		if ( bSaveKey ) then
    			v.__key = k
    		table.insert( OutTable, v )	
    	return OutTable

    SortedPairsByMemberValue calls table.ClearKeys:

       A Pairs function
    		Sorted by Member Value (All table entries must be a table!)
    function SortedPairsByMemberValue( pTable, pValueName, Desc )
    	Desc = Desc or false
    	local pSortedTable = table.ClearKeys( pTable, true )
    	table.SortByMember( pSortedTable, pValueName, !Desc )
    	local SortedIndex = {}
    	for k, v in ipairs( pSortedTable ) do
    		table.insert( SortedIndex, v.__key )
    	pTable.__SortedIndex = SortedIndex
    	return fnPairsSorted, pTable, nil

    Maybe I shouldn't bother with trying to organize the table right here, but rather when the function generates the icons?