Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua sort table alphabetically, except numbers

I would want to sort a table alphabetically. Except numbers.

The code below shows how the table is sorted with comparator function:

function( a,b ) return a.N < b.N end

Gives me:

obj = {
    [1] = {
        ["N"] = "Green 1";
    };
    [2] = {
        ["N"] = "Green 11";
    };
    [3] = {
        ["N"] = "Green 2";
    };
    [4] = {
        ["N"] = "Red 1";
    };
}

But I want it to be sorted like this:

obj = {
    [1] = {
        ["N"] = "Green 1";
    };
    [2] = {
        ["N"] = "Green 2";
    };
    [3] = {
        ["N"] = "Green 11";
    };
    [4] = {
        ["N"] = "Red 1";
    };
}

Is it possible?

like image 210
Dreanh Avatar asked Jan 12 '15 19:01

Dreanh


3 Answers

Try this:

local function split(a)
    local x,y=a.N:match("(%S+)%s+(%S+)")
    return x,tonumber(y)
end

table.sort(obj,
    function (a,b)
        local a1,a2=split(a)
        local b1,b2=split(b)
        return a1<b1 or (a1==b1 and a2<b2)
    end
)
like image 191
lhf Avatar answered Oct 04 '22 21:10

lhf


Was going to post this originally, but the solution posted by lhf answered your question. Since you are still having issues, give the following a try.

local function cmp(a, b)
   a = tostring(a.N)
   b = tostring(b.N)
   local patt = '^(.-)%s*(%d+)$'
   local _,_, col1, num1 = a:find(patt)
   local _,_, col2, num2 = b:find(patt)
   if (col1 and col2) and col1 == col2 then
      return tonumber(num1) < tonumber(num2)
   end
   return a < b
end

local obj = {
   { N = '1'           },
   { N = 'Green1'      }, -- works with optional space
   { N = 'Green'       }, -- works when doesn't fit the format
   { N = 'Sky blue99'  },
   { N = 'Green 11'    },
   { N = 'Green 2'     },
   { N = 'Red 02'      }, -- works when has leading zeros
   { N = 'Red    01'   }, -- works with padding spaces
   { N = 'Sky blue 42' }, -- works with multi-word color names
   { N = 99            }, -- works with numbers
}

table.sort(obj, cmp)
for i,v in ipairs(obj) do
   print(i, v.N)
end

Prints:

1   1
2   99
3   Green
4   Green1
5   Green 2
6   Green 11
7   Red    01
8   Red 02
9   Sky blue 42
10  Sky blue99
like image 28
Adam Avatar answered Oct 04 '22 21:10

Adam


@lhf's solution should work for you, although you may need to consider if you need to handle corner cases, like comparing "Green 1" with "Green 02" or "Green 2" with "Green 02". I've reviewed several methods to implement alphanum sorting and compared their results in a blog post. You may also check the discussion on the lua mail list on this very topic.

like image 32
Paul Kulchenko Avatar answered Oct 04 '22 23:10

Paul Kulchenko