Сповіщення
Очистити все

Таблиці


Ранг:
Майстер
Роль:
Гість
Записи:
752
Приєднався:
2 роки тому
 

Таблиця в 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) спаунеться певний предмет зі списку. У цю таблицю можна внести як сталкерів, і мутантів.


   
Цитата