Не удается отсортировать таблицу по ассоциативным индексам

StackOverflow https://stackoverflow.com/questions/2097411

Вопрос

Почему я не могу использовать table.сортировать для сортировки таблиц с ассоциативными индексами?

Это было полезно?

Решение

Вы можете сортировать таблицы только по последовательным целочисленным ключам, начинающимся с 1, то есть по спискам.Если у вас есть другая таблица пар ключ-значение, вы можете составить список пар и отсортировать их:

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

Конечно, это полезно только в том случае, если вы предоставляете индивидуальный заказ (lt) который ожидает в качестве аргументов пары ключ / значение.

Этот вопрос более подробно обсуждается в связанный вопрос о сортировке таблиц Lua.

Другие советы

В общем, таблицы Lua представляют собой чистые ассоциативные массивы.Не существует "естественного" порядка, отличного от побочного эффекта конкретной реализации хэш-таблицы, используемой в ядре Lua.Это имеет смысл, поскольку значения любого типа данных Lua (кроме nil) может использоваться как в качестве ключей , так и в качестве значений;но только строки и числа имеют какой-либо разумный порядок, и то только между значениями подобного типа.

Например, каким должен быть порядок сортировки этой таблицы:

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

Он содержит один строковый ключ, один логический ключ, одну функциональную клавишу, один нецелочисленный ключ, один табличный ключ и пять целочисленных ключей.Должна ли функция сортировать перед строкой?Как вы сравниваете строку с числом?Где должна быть отсортирована таблица?И что насчет userdata и thread значения, которых случайно нет в этой таблице?

По соглашению, значения, индексированные последовательными целыми числами, начинающимися с 1, обычно используются в виде списков.Несколько функций и распространенных идиом следуют этому соглашению, и table.sort это один из примеров.Функции, работающие со списками, обычно игнорируют любые значения, хранящиеся в ключах, которые не являются частью списка.Снова, table.sort является примером:он сортирует только те элементы, которые хранятся по ключам, являющимся частью списка.

Другим примером является # оператор.Для приведенной выше таблицы, #unsortable равно 5, потому что unsortable[5] ~= nil и unsortable[6] == nil.Обратите внимание, что значение, хранящееся в числовом индексе math.pi не учитывается, даже если число pi находится между 3 и 4, потому что оно не является целым числом.Кроме того, ни один из других нецелочисленных ключей также не учитывается.Это означает, что простой цикл for может выполнять итерацию по всему списку:

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

Хотя это часто пишется как

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

Короче говоря, таблицы Lua представляют собой неупорядоченные наборы значений, каждое из которых индексируется ключом;но существует специальное соглашение для последовательных целочисленных ключей, начинающихся с 1.

Редактировать: Для особого случая нецелых ключей с подходящим частичным упорядочением существует обходной путь, включающий отдельную таблицу индексов.Описанное содержимое таблиц, разделенных строковыми значениями, является подходящим примером для этого трюка.

Сначала соберите ключи в новую таблицу, в виде списка.То есть создайте таблицу, проиндексированную последовательными целыми числами, начинающимися с 1, с ключами в качестве значений и отсортируйте их.Затем используйте этот индекс для перебора исходной таблицы в нужном порядке.

Например, вот foreachinorder(), который использует этот метод для перебора всех значений таблицы, вызывая функцию для каждой пары ключ / значение, в порядке, определяемом функцией сравнения.

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

Он создает индекс, сортирует его с помощью table.sort(), затем перебирает каждый элемент в отсортированном индексе и вызывает функцию f для каждого из них.Функция f передается ключ и значение.Порядок сортировки определяется необязательной функцией сравнения, которая передается в table.sort.Он вызывается с двумя элементами для сравнения (ключами к таблице t в этом случае) и должен вернуть true если первое меньше второго.Если опущено, table.sort использует встроенный < оператор.

Например, приведена следующая таблица:

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

тогда foreachinorder(t1,print) С принтами:

a    1
b    2
c    3

и foreachinorder(t1,print,function(a,b) return a>b end) С принтами:

c    3
b    2
a    1

Потому что у них вообще нет никакого порядка.Это все равно что пытаться рассортировать мусорный пакет, набитый бананами.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top