Таблицы. Что это такое и с чем его едят. Часть 1. — различия между версиями — S.T.A.L.K.E.R. Inside Wiki

Таблицы. Что это такое и с чем его едят. Часть 1. — различия между версиями

Материал из S.T.A.L.K.E.R. Inside Wiki

Перейти к: навигация, поиск
(Обход элементов хэш-таблицы)
(Обход элементов хэш-таблицы)
Строка 126: Строка 126:
 
Об ошибках, связанных с циклами по таблицам см. в статье '''KamikaZze''' [[ Как писать скрипты, не приводящие к вылетам и бою сейвов#Смертельные циклы по таблицам|здесь]]
 
Об ошибках, связанных с циклами по таблицам см. в статье '''KamikaZze''' [[ Как писать скрипты, не приводящие к вылетам и бою сейвов#Смертельные циклы по таблицам|здесь]]
  
Хотя лично я не согласен с утверждением, что "ни при каких обстоятельствах не используйте внутри этого цикла удаление/добавление строк".
+
Хотя лично я не согласен с утверждением, что "ни при каких обстоятельствах не используйте внутри этого цикла удаление/добавление строк" и "следует использовать только для операций, не изменяющих структуру изменяемой таблицы!".
 
Правильнее было бы сказать, что "ни при каких обстоятельствах не изменяйте длину массива внутри этого цикла".
 
Правильнее было бы сказать, что "ни при каких обстоятельствах не изменяйте длину массива внутри этого цикла".
 
Т.е. "смертельный" вариант :
 
Т.е. "смертельный" вариант :

Версия 20:31, 7 мая 2013

Итак. Большинство модеров которые начинают осваивать скриптинг сталкера сталкиваются с таким понятием как таблицы.

Таблицы

Таблица в 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. Для обычного массива, оператор # вернет количество элементов в массиве.

Обход элементов массива

Для обхода элементов массива используется как простая, так и расширенная форма записи оператора for (см. 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 именованной

Обход элементов хэш-таблицы

Обход осуществляется только расширенной формой оператора for с использование функции-итератора 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 ...

Gun12

P.S. То, что ниже, это остатки первоначальной статьи, верхнюю часть которой я безжалостно вырезал за несоответствие названию статьи.


К примеру:

local variables = {1, 2}

Примечание: таблицы можно использовать как за функцией, так и внутри неё. В нашем случае таблица содержит набор чисел 1 и 2. Что же с ними можно сделать?

function table()
local variables= {1, 2} --наша таблица
rezultat = variables[math.random(table.getn(variables))] --rezultat локальная переменная.
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,win_text, nil, nil, 10000) and 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,win_text, nil, nil, 10000) and 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)
end

Как видите таблица используется вне функции, но можно и в самой функции. В данном примере в определённой точке с координатами (-0.112,0.477,-215.563),174943,265) заспаунится определённый предмет из списка. В эту таблицу можно внести как сталкеров, так и мутантов.

Позже продолжу. iDreD aka кровоSTALKER.

Другие места
LANGUAGE