Таблиця в Lua – це базовий тип даних. І навіть не так. Це фундаментальна основа мови, яка визначає чи не всі можливості Lua.
Таблиці можуть використовуватися як звичайні масиви, таблиці символів, множини, поля записів, дерева і таке інше.
Причому оскільки функції відносяться до значень першого класу, поля таблиці можуть містити і функції. Отже, таблиці можуть зберігати методи.
Механізми реалізації типу «таблиця» або асоціативний масив Lua дуже ефективні.
Наприклад, обчислення знаменитої рекурсивної функції Аккермана на Lua значно швидше, ніж на Perl і Ruby, і вп'ятеро – ніж на Python.
Швидкість обчислення хеш-функцій (з використанням механізму хешування і будуються Lua-таблиці) у Lua майже бездоганна – інтерпретовані Lua-програми справляються з цим завданням менш ніж удвічі повільніше написаних мовою C.
Визначення
Таблиця є асоціативним масивом (набір пар ключ-значення). Ключем (індексом) та значенням може бути будь-який тип даних, що використовуються в Lua (за винятком nil ).
Конструктор таблиці
Конструктор використовується для створення таблиць і є список полів у фігурних дужках.
Поля відокремлюються один від одного комами (" , ") або крапками з комою (" ; "). У цьому допускається наявність роздільника після останнього поля.
Таблиця може бути проініціалізована під час створення (стандартний конструктор таблиці):
t1 = { } - порожня таблиця t2 = { 1 , 5 , 7 , 'abc' } - звичайний масив t3 = { x = 7 , y = "6" } - таблиця з іменованими полями '''x'' ' і '''y''' t4 = { 1 , ' string ', x = 77 } -- змішана таблиця t5 = { 1 , xxx = 17 , } -- роздільник у кінці допустимо
Або заповнена пізніше, ініціалізуючи кожну пару ключ-значення:
t4 = { } t4 [ 1 ] = 1 - Визначає число 1 на місце, що індексується номером 1 t4 [ 2 ] = ' string ' - Визначає рядок 'string' на місце, що індексується номером 2 t4 [ 'x' ] = 77 -- Визначає число 77 на місце, що індексується рядком 'x'
Для зручності роботи можна замість індексування таблиці на ім'я (рядок) використовувати це ім'я як ім'я поля структури:
t4 [ 'x' ] = 77 t4.x = 77
Ці дві форми звернення є повністю еквівалентними.
Масив
Щоб отримати звичайний масив (таблиця t2), просто задаються значення елементів. Ключі будуть встановлені автоматично.
У Lua звичайні масиви індексуються цілими, послідовно наростаючими числами починаючи з одиниці. Приклади нижче еквівалентні.
t2 = { 1 , 5 , 7 , 'abc' } t2 = { [ 1 ] = 1 , [ 2 ] = 5 , [ 3 ] = 7 , [ 4 ] = 'abc' } t2 = { } t2 [ 1 ] = 1 t2 [ 2 ] = 5 t2 [ 3 ] = 7 t2 [ 4 ] = 'abc'
Поки можливо, Lua у собі таблицю зберігає як масив, а чи не як хеш - таблицю.
У цьому випадку доступ до елементів таблиці відбувається майже так само швидко, як у масивах Сі. Тому без особливої потреби не потрібно перетворювати масив на хеш.
Для того, щоб не порушувати структуру при додаванні та видаленні елементів масиву, варто користуватися бібліотекою Lua table .
local t = { 1 , 2 , 3 , 4 , 5 } table.insert ( t , 6 ) - додає елемент до кінця масиву. t = {1, 2, 3, 4, 5, 6} table.insert ( t, 0 , 1 ) - вставляє елемент за індексом, зрушуючи елементи масиву, що залишилися. t = {0, 1, 2, 3, 4, 5, 6} table . remove ( t, 3 ) - видаляє з таблиці елемент за індексом 3 і зрушує елементи, що залишилися. t = {0, 1, 3, 4, 5, 6}
Розмір масиву
Отримання розміру масиву виконується оператором # :
local count = #t
Оператор # повертає ціле число n, таке, що t [n] не nil і t [n + 1] дорівнює nil . Тобто оператор # , повертає максимальний індекс безперервної послідовності ключів від початку масиву.
Відповідно, для таблиці:
t = { 1 , [ 100 ] = 2 }
довжина дорівнюватиме 1, оскільки t[1] не nil , а t[1 + 1] дорівнює nil . Для звичайного масиву оператор # поверне кількість елементів у масиві.
Обхід елементів масиву
Для обходу елементів масиву використовується як проста, так і розширена форма запису оператора ( див . http://www.lua.ru/doc/2.4.5.html )
for i = 1 , #t do ... end
Цикл обійде всі поля масиву від поля з індексом 1 (i=1) до останнього індексу поля (#t), що визначається оператором # (див. "Розмір масиву")
Або розширена форма з використанням функції-ітератора ipairs :
for key,value in ipairs ( t ) do ... end
Функція-ітератор ipairs повертає два значення. Перше – ключ цього поля, друге – значення.
При знаходженні кожного наступного поля ці значення присвоюються змінним key і value .
Хеш-таблиці
Таліці, що не підпадають під визначення масиву, є хеш-таблицями. Індексами таких таблиць є об'єкти різних типів (крім nil ).
Дізнатися кількість елементів такої таблиці, крім обійшовши їх усі, не можна.
Будова хеш-таблиці
Будь-яка хеш-таблиця складається з двох частин - індексованої та іменованої. Індексована частина підпорядковується законам масиву (див. вище), іменована - включає індекси (ключі), які неможливо включити до індексованої частини, не порушуючи її будови. Наприклад для таблиці:
t = { a = 1 , b = 2 }
Існує індексована частина. Підтвердити це можна викликавши оператор '#', призначений визначення довжини:
print ( #t ) -> 0
Тобто. оператор '#' визначив (хоч і нульову, але) довжину. Перевіривши таблицю:
t = { a = 1 , b = 2 , 'one' }
Довжина дорівнюватиме 1, т.к. з'явилося поле з індексом - [1], і значенням - 'one' (автоматичне призначення індексу. див. вище) Жодне з двох інших полів цієї таблиці не може бути частиною масиву, разом з полем [1]='one', т .к. їх індекси не відповідають індексу номером [2]. Тому:
- частина 'one' буде індексованою частиною.
- частина a=1 та b=2 іменованої
Обхід елементів хеш-таблиці
Обхід здійснюється тільки розширеною формою оператора для використання функції-ітератора pairs .
Ця функція дозволяє обійти елементи будь-яких таблиць (включно з масивами). Значення, що повертаються такі ж, як і для функції ipairs :
for k,v in pairs ( t ) do ... end
У цьому завжди спочатку визначаються поля індексованої частини як масиву, та був іменованої.
Про помилки, пов'язані з циклами за таблицями див. у статті KamikaZze тут
Хоча особисто я не згоден із твердженням, що "за жодних обставин не використовуйте всередині цього циклу видалення/додавання рядків" і "слід використовувати тільки для операцій, що не змінюють структуру таблиці, що змінюється!". Правильніше було б сказати, що "за жодних обставин не змінюйте довжину масиву всередині цього циклу". Тобто. "смертельний" варіант:
for i = i, #t do table . remove ( t, i ) end
в, якому з кожним "оборотом" зменшується довжина масиву, стає найшвидшим і оптимальним у випадку...ну, наприклад, реверсування масиву:
local len = t for i = len -1 , 1 , -1 do t [ len ] = table . remove ( t, i ) end
у якому довжина масиву не змінюється.
to be continue ...
Nazgool
PS Те, що нижче, це залишки первісної статті, верхню частину якої я безжально вирізав за невідповідність назві статті.
Наприклад:
local variables = { 1,2 } _
Примітка : таблиці можна використовувати як за функцією, так і всередині неї. У разі таблиця містить набір чисел 1 і 2. Що з ними можна зробити?
function table ( ) local variables = { 1 , 2 } -- наша таблиця rezultat = variables [ math . random ( table . getn ( variables ) ) ] - resultat локальна змінна. if rezultat == 1 then news_manager.send_tip ( db.actor,lose_text, nil , nil , 10000 ) and db.actor:give_info_portion ( "lose" ) end if rezultat == 2 then news_manager.send_tip ( db,actor nil , nil , 10000 ) і db.actor:give_info_portion ( "win" ) end end
Поясню: variables[math.random(table.getn(variables))] цей оператор дозволяє взяти рандомне значення цієї таблиці. Тобто випадково взяти або число 1, або число 2.
if rezultat == 1 then news_manager.send_tip ( db.actor,lose_text, nil , nil , 10000 ) and db.actor:give_info_portion ( "lose" ) end if rezultat == 2 then news_manager.send_tip ( db,actor nil , nil , 10000 ) і db.actor:give_info_portion ( "win" ) end
Визначає значення, взяте з таблиці, і в залежності від результату надсилає нам те чи інше повідомлення (news_manager.send_tip(db.actor,, nil, nil, 10000)) і дає той чи інший інфопоршень (db.actor:give_info_portion( "") end).
== - Це оператор порівняння. У нашому випадку це "рівно". Також є оператори:
> - більше.
< - менше.
>= - більше чи одно.
<= - менше чи одно.
~= - не однаково.
Порівнювати можна лише числа чи локальні змінні з присвоєними до них числами.
На цьому прикладі можна створити найпростішу функцію спауна:
local stalker_types = { "bread" , "kolbasa" , "conserva" , "vodka" } function spawn_item ( ) alife ( ) : create ( stalker_types [ math . random ( 4 ) ] , vector ( ) : set ( -0.112 , 0.477 , -215.563 ) , 174943 , 265 )
Як бачите таблиця використовується поза функцією, але можна і в самій функції. У цьому прикладі в певній точці з координатами (-0.112,0.477,-215.563),174943,265) спаунеться певний предмет зі списку. У цю таблицю можна внести як сталкерів, і мутантів.