How to sort a table on 2 values?

Hi,

I’m trying to sort a table alphabetically on 2 values, but so far no luck.

The table should be sorted on category and within a certain category range the name field should also be sorted.

So all category “bread” should be on top and within this category all name values should also be sorted alphabetically. 

local food =    { 

                {category = “Bread”, name = “white”},

                {category = “drinks”, name = “cola”},

                {category = “Bread”, name = “corn”},

                {category = “Bread”, name = “french”},

                {category = “drinks”, name = “milk”},

                {category = “drinks”, name = “soda”}

                }

via :

local function tableSortCat (a,b) return a.category \< b.category end table.sort( foodlist, tableSortCat)

I’m able to sort on category only but not both.

Can anyone help me to solve this?

Thanks!

Here you go.  Tested and working.

[lua]

local food =    { 

                {category = “Bread”, name = “white”},

                {category = “drinks”, name = “cola”},

                {category = “Bread”, name = “corn”},

                {category = “Bread”, name = “french”},

                {category = “drinks”, name = “soda”},

                {category = “drinks”, name = “milk”}

                }

   

local function tableSortCat (a, b )

    if (a.category < b.category) then

           return true

        elseif (a.category > b.category) then

            return false

        else

              return a.name < b.name

        end

end

table.sort( food, tableSortCat)       

                

for i=1,#food do

    print (food[i].category,food[i].name)

end                

[/lua]

I think you could collapse the sort function to this:

local function tableSortCat (a, b ) return (a.category \< b.category) or (a.category == b.category and a.name \< b.name) end

I’ve not tested this.

Wow! Already some replies.   :slight_smile:

@ Icy Spark:

It works!!

but…

I’m not able to understand what is happening in your sort function.

Could you maybe explain a little bit?

Many Thanks!!

@ horacebury: 

Thanks for your reply. In your sort function the category are correctly sorted but the names not.

With this code:

local food = { {category = "Bread", name = "white"}, {category = "drinks", name = "cola"}, {category = "Bread", name = "corn"}, {category = "Bread", name = "french"}, {category = "drinks", name = "milk"}, {category = "drinks", name = "soda"} } local function tableSortCat( a, b ) return (a.category \< b.category) or (a.category == b.category and a.name \< b.name) end table.sort( food, tableSortCat ) for i=1, #food do print(food[i].category, food[i].name) end

I get this result:

Bread corn Bread french Bread white drinks cola drinks milk drinks soda

Which looks right to me. The categories are sorted in alphabetical order and under the categories then individual foods are alphabetical.

What are you looking for?

Hi Horace,  I haven’t checked your code but the drinks names seem to be in order because they are already in order as you have added them to your initial table?

Hence the reason I moved soda above milk for my test.

Give it a whirl when the drinks names are not in order.

Yes, the drinks are already in order, but the foods are not and they get sorted just fine. I unordered the drinks just to check and they also get sorted properly:

local food = { {category = "Bread", name = "white"}, {category = "drinks", name = "milk"}, {category = "Bread", name = "corn"}, {category = "Bread", name = "french"}, {category = "drinks", name = "cola"}, {category = "drinks", name = "soda"} } local function tableSortCat( a, b ) return (a.category \< b.category) or (a.category == b.category and a.name \< b.name) end table.sort( food, tableSortCat ) for i=1, #food do print(food[i].category, food[i].name) end

Sorted to:

Bread corn Bread french Bread white drinks cola drinks milk drinks soda

So I believe that my solution works.

All I did in the function is to compress the logic of the multiple if statements in Icy Spark’s logic. This took a bit of double-checking because the short-circuiting nature of if statements can lead coders to miss things, but I think I got it in the end. It’s a good mental exercise to go through.

Here you go.  Tested and working.

[lua]

local food =    { 

                {category = “Bread”, name = “white”},

                {category = “drinks”, name = “cola”},

                {category = “Bread”, name = “corn”},

                {category = “Bread”, name = “french”},

                {category = “drinks”, name = “soda”},

                {category = “drinks”, name = “milk”}

                }

   

local function tableSortCat (a, b )

    if (a.category < b.category) then

           return true

        elseif (a.category > b.category) then

            return false

        else

              return a.name < b.name

        end

end

table.sort( food, tableSortCat)       

                

for i=1,#food do

    print (food[i].category,food[i].name)

end                

[/lua]

I think you could collapse the sort function to this:

local function tableSortCat (a, b ) return (a.category \< b.category) or (a.category == b.category and a.name \< b.name) end

I’ve not tested this.

Wow! Already some replies.   :slight_smile:

@ Icy Spark:

It works!!

but…

I’m not able to understand what is happening in your sort function.

Could you maybe explain a little bit?

Many Thanks!!

@ horacebury: 

Thanks for your reply. In your sort function the category are correctly sorted but the names not.

With this code:

local food = { {category = "Bread", name = "white"}, {category = "drinks", name = "cola"}, {category = "Bread", name = "corn"}, {category = "Bread", name = "french"}, {category = "drinks", name = "milk"}, {category = "drinks", name = "soda"} } local function tableSortCat( a, b ) return (a.category \< b.category) or (a.category == b.category and a.name \< b.name) end table.sort( food, tableSortCat ) for i=1, #food do print(food[i].category, food[i].name) end

I get this result:

Bread corn Bread french Bread white drinks cola drinks milk drinks soda

Which looks right to me. The categories are sorted in alphabetical order and under the categories then individual foods are alphabetical.

What are you looking for?

Hi Horace,  I haven’t checked your code but the drinks names seem to be in order because they are already in order as you have added them to your initial table?

Hence the reason I moved soda above milk for my test.

Give it a whirl when the drinks names are not in order.

Yes, the drinks are already in order, but the foods are not and they get sorted just fine. I unordered the drinks just to check and they also get sorted properly:

local food = { {category = "Bread", name = "white"}, {category = "drinks", name = "milk"}, {category = "Bread", name = "corn"}, {category = "Bread", name = "french"}, {category = "drinks", name = "cola"}, {category = "drinks", name = "soda"} } local function tableSortCat( a, b ) return (a.category \< b.category) or (a.category == b.category and a.name \< b.name) end table.sort( food, tableSortCat ) for i=1, #food do print(food[i].category, food[i].name) end

Sorted to:

Bread corn Bread french Bread white drinks cola drinks milk drinks soda

So I believe that my solution works.

All I did in the function is to compress the logic of the multiple if statements in Icy Spark’s logic. This took a bit of double-checking because the short-circuiting nature of if statements can lead coders to miss things, but I think I got it in the end. It’s a good mental exercise to go through.