2015-01-12 2 views
5

Я бы хотел отсортировать таблицу по алфавиту. Кроме номеров.Lua сортировать таблицу по алфавиту, за исключением номеров

Приведенный ниже код показывает, как таблица сортируется с функцией сравнения:

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

дает мне:

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

Но я хочу, чтобы это быть отсортированы так:

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

Возможно ли это?

+0

Удалить все номера из ключа, прежде чем сортировать? Сортировка только по первому слову? и т. д. Если ваша таблица большая или вы собираетесь делать это, часто сохраняя кеш «сортируемого ключа», который вы создаете, вероятно, тоже хорошая идея. –

ответ

3

Собирался опубликовать это изначально, но решение, отправленное lhf, ответило на ваш вопрос. Поскольку у вас все еще есть проблемы, попробуйте следующее.

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 

Печать:

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 
+0

Спасибо, это работает лучше. Изменен шаблон: ''^(% D +) (% d +) $ '', чтобы разрешить' {N =' Green1 '}, 'похоже, работает, но, возможно, что-то упустил. – Dreanh

+0

@Dreanh Этот шаблон выглядит хорошо и должен работать до тех пор, пока в имени цвета нет цифр, (. +) Работает для любого символа (ов). – Adam

+0

Хорошо, спасибо. Если я использую ''^(. +) (% D +) $ ''или''^(% g) (% d +) $ '', он не работает. – Dreanh

6

Попробуйте это:

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 
) 
+0

Спасибо! Это сработало так, как я этого хотел! – Dreanh

+0

Получил проблему, хотя, не упомянул, что некоторые строки в таблице не получили номера. Поэтому я получаю сообщение об ошибке. – Dreanh

+0

Получите ошибку в этой строке: 'return a1 Dreanh

3

@ решение LHF должно работать для вас, хотя вы, возможно, потребуется рассмотреть, если вам нужно обработать угловые случаи, как сравнение «Зеленый 1» с «Green 02» или «Зеленый 2 "с" Зеленый 02 ". Я рассмотрел несколько методов для реализации сортировки по алфавиту и сравнил их результаты с blog post. Вы также можете проверить discussion on the lua mail list по этой теме.