Функции библиотеки table в Lua

Опубликовано:

table — одна из стандартных библиотек Lua, представляет собой модуль (набор функций) для управления индексированными таблицами (массивами), то есть ее функции почти не подходят для хэш-таблиц. Для последних операции выполняются стандартным синтаксисом языка.

Добавление и удаление элементов

Функции table.insert и table.remove используются для динамического изменения последовательностей. Данные операции можно считать одними из наиболее частых.

local inventory = {"Меч", "Щит"}

-- table.insert(таблица, [позиция], значение)
table.insert(inventory, "Зелье") -- Добавит в конец
table.insert(inventory, 1, "Шлем") -- Вставит на 1-е место, остальное сдвинет

print(table.concat(inventory, ", "))

-- table.remove(таблица, [позиция])
local removed = table.remove(inventory, 2) -- Удалит "Меч" и вернет его

print("Удалено:", removed)
print(table.concat(inventory, ", "))
Шлем, Меч, Щит, Зелье
Удалено:        Меч
Шлем, Щит, Зелье

Быстрое объединение в строку

Функция table.concat — лучший способ быстро вывести содержимое списка (например, при формировании логов).

local words = {"one", "two", "three", "four"}

-- Склеиваем элементы через пробел
local sentence = table.concat(words, " ")
print(sentence)

-- Можно указать диапазон индексов
local short = table.concat(words, " ", 3, 4)
print(short)
one two three four
three four

Следует использовать table.concat вместо соединения строк через .. в циклах, так как оно там не только медленное, но и расходует память. В примере ниже на каждой итерации цикла создается абсолютно новая строка в памяти, а старая выбрасывается. Если итераций много (например, сборка логов, генерация HTML или больших текстов), подобный код начнет тормозить программу и перегружать сборщик мусора (garbage collector).

local words = {'one', 'two', 'three', 'four', 'five', 'six', 'seven'}

-- АНТИПРИМЕР: Склеивание через оператор '..' в цикле
local result = ''
for i = 1, #words do
    -- Нельзя изменить существующую строку 'result',
    -- поэтому каждый раз выделяется новая память под 'result .. words[i] + пробел'
    result = result .. words[i] .. ''
end

print(string.len(result)) -- 34

Сортировка массивов (списков, последовательностей)

Функция table.sort — это единственный стандартный способ отсортировать таблицу-массив в Lua. По умолчанию сортирует числа по возрастанию, а строки — по алфавиту. Для сложных структур нужно передавать свою функцию сравнения, то есть программист должен уметь писать кастомные функции сравнения (например, для сортировки объектов).

-- Простая сортировка
local numbers = {5, 2, 9, 1}
table.sort(numbers)
print(table.concat(numbers, ", ")) -- Вывод: 1, 2, 5, 9

-- Сортировка сложных объектов (таблиц внутри таблицы)
local players = {
    {name = "Alex", level = 50},
    {name = "Elena", level = 85},
    {name = "Ivan", level = 12}
}

-- Сортируем игроков по уровню (от большего к меньшему)
table.sort(players, function(a, b)
    return a.level > b.level
end)

for _, player in ipairs(players) do
    print(player.name .. " (" .. player.level .. ")")
end
-- Вывод:
-- Elena (85)
-- Alex (50)
-- Ivan (12)

Распаковка элементов таблиц и упаковка значений в таблицу

Функции table.unpack и table.pack полезны, когда нужно передать элементы таблицы как аргументы в функцию или, наоборот, собрать аргументы в таблицу.

-- table.unpack превращает массив в список аргументов
local coordinates = {10, 20, 30}

-- math.max(10, 20, 30)
local max_val = math.max(table.unpack(coordinates)) 
print(max_val) -- Вывод: 30

-- table.pack собирает аргументы и автоматически добавляет поле "n" (количество элементов)
-- Это критически важно, если среди аргументов может быть nil
local my_pack = table.pack("A", nil, "C")
print(my_pack.n) -- Вывод: 3 (хотя внутри есть nil)

Копирование подмножества элементов

Функция table.move появилась в Lua 5.3 и является одним из самых быстрых инструментов для копирования срезов. Она берет диапазон элементов из одной таблицы и вставляет их в другую (или в ту же самую) на указанную позицию.

Клонирование массива (или его части):

local source = {"яблоко", "банан", "груша", "слива"}
local target = {}

-- Копируем с 1 по 3 элемент из source в target,
-- начиная с 1-й позиции target
table.move(source, 1, 3, 1, target)

print(table.concat(target, ", "))
яблоко, банан, груша

Слияние двух массивов путем добавления всех элементов одного массива в конец другого.

local inventory = {"Меч", "Щит"}
local loot = {"Зелье", "Золото", "Руна"}

-- Копируем весь loot в конец inventory
-- Начинаем вставлять на позицию (#inventory + 1), то есть на индекс 3
table.move(loot, 1, #loot, #inventory + 1, inventory)

print(table.concat(inventory, ", "))
Меч, Щит, Зелье, Золото, Руна

table.move умеет корректно перемещать элементы внутри одной и той же таблицы, даже если области копирования пересекаются. Это позволяет эффективно удалять элементы из середины массива без использования медленной table.remove. Допустим, мы хотим удалить 2-й элемент ("Б") из массива, сдвинув все элементы после него влево:

local alphabet = {"А", "Б", "В", "Г", "Д"}

-- Сдвигаем элементы с 3 по 5 на одну позицию влево (начиная с индекса 2)
table.move(alphabet, 3, 5, 2)

-- Последний элемент продублировался, зануляем его вручную
alphabet[5] = nil

print(table.concat(alphabet, ", "))
А, В, Г, Д