Pergunta

Por que não posso usar table.sort para classificar tabelas com índices associativos?

Foi útil?

Solução

Você só pode classificar tabelas com teclas inteiras consecutivas a partir de 1, ou seja, listas. Se você tiver outra tabela de pares de valores-chave, poderá fazer uma lista de pares e classificar isso:

function sortpairs(t, lt)
  local u = { }
  for k, v in pairs(t) do table.insert(u, { key = k, value = v }) end
  table.sort(u, lt)
  return u
end

Claro que isso é útil apenas se você fornecer um pedido personalizado (lt) que esperam como pares de chave/valor de argumentos.

Esta questão é discutida em maior comprimento em um Pergunta relacionada sobre a classificação das mesas Lua.

Outras dicas

Em geral, as tabelas Lua são matrizes associativas puras.Não há nenhuma ordem "natural" além do efeito colateral da implementação específica da tabela hash usada no núcleo Lua.Isso faz sentido porque valores de qualquer tipo de dados Lua (exceto nil) podem ser usados ​​como chaves e valores;mas apenas strings e números têm algum tipo de ordem sensata, e apenas entre valores do mesmo tipo.

Por exemplo, qual deveria ser a ordem de classificação desta tabela:

unsortable = {
    answer=42,
    true="Beauty",
    [function() return 17 end] = function() return 42 end,
    [math.pi] = "pi",
    [ {} ] = {},
    12, 11, 10, 9, 8
}

Possui uma chave de string, uma chave booleana, uma tecla de função, uma chave não integral, uma chave de tabela e cinco chaves inteiras.A função deve ser classificada antes da string?Como você compara a string a um número?Onde a tabela deve ser classificada?E sobre userdata e thread valores que não aparecem nesta tabela?

Por convenção, valores indexados por inteiros sequenciais começando com 1 são comumente usados ​​como listas.Várias funções e idiomas comuns seguem esta convenção, e table.sort é um exemplo.Funções que operam em listas geralmente ignoram quaisquer valores armazenados em chaves que não fazem parte da lista.De novo, table.sort é um exemplo:ele classifica apenas os elementos armazenados nas chaves que fazem parte da lista.

Outro exemplo é o # operador.Para a tabela acima, #unsortable é 5 porque unsortable[5] ~= nil e unsortable[6] == nil.Observe que o valor armazenado no índice numérico math.pi não é contado mesmo que pi esteja entre 3 e 4 porque não é um número inteiro.Além disso, nenhuma das outras chaves não inteiras também é contada.Isso significa que um loop for simples pode iterar por toda a lista:

for i in 1,#unsortable do
    print(i,unsortable[i])
end

Embora isso seja frequentemente escrito como

for i,v in ipairs(unsortable) do
    print(i,v)
end

Resumindo, as tabelas Lua são coleções não ordenadas de valores, cada um indexado por uma chave;mas existe uma convenção especial para chaves inteiras sequenciais começando em 1.

Editar: Para o caso especial de chaves não integrais com uma ordenação parcial adequada, existe uma solução alternativa que envolve uma tabela de índices separada.O conteúdo descrito de tabelas codificadas por valores de string é um exemplo adequado para esse truque.

Primeiro, reúna as chaves em uma nova tabela, em forma de lista.Ou seja, faça uma tabela indexada por números inteiros consecutivos começando em 1 com chaves como valores e classifique-a.Em seguida, use esse índice para iterar na tabela original na ordem desejada.

Por exemplo, aqui está foreachinorder(), que usa essa técnica para iterar todos os valores de uma tabela, chamando uma função para cada par chave/valor, em uma ordem determinada por uma função de comparação.

function foreachinorder(t, f, cmp)
    -- first extract a list of the keys from t
    local keys = {}
    for k,_ in pairs(t) do
        keys[#keys+1] = k
    end
    -- sort the keys according to the function cmp. If cmp
    -- is omitted, table.sort() defaults to the < operator
    table.sort(keys,cmp)
    -- finally, loop over the keys in sorted order, and operate
    -- on elements of t
    for _,k in ipairs(keys) do
        f(k,t[k])
    end
end

Ele constrói um índice, classifica-o com table.sort(), em seguida, faz um loop sobre cada elemento no índice classificado e chama a função f para cada um.A função f é passada a chave e o valor.A ordem de classificação é determinada por uma função de comparação opcional que é passada para table.sort.É chamado com dois elementos para comparar (as chaves da tabela t neste caso) e deve retornar true se o primeiro for menor que o segundo.Se omitido, table.sort usa o integrado < operador.

Por exemplo, dada a seguinte tabela:

t1 = {
    a = 1,
    b = 2,
    c = 3,
}

então foreachinorder(t1,print) impressões:

a    1
b    2
c    3

e foreachinorder(t1,print,function(a,b) return a>b end) impressões:

c    3
b    2
a    1

Porque eles não têm nenhum pedido em primeiro lugar. É como tentar classificar um saco de lixo cheio de bananas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top