Как правило, таблицы 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
, не учитывается, даже если число от 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