Прежде всего, если ваша таблица balls
представляет собой таблицу, подобную массиву, или вы хотите выполнить итерацию только по части массива, вам лучше использовать ipairs
или стандартный for i
. pairs
перебирает все индексы таблицы, включая нечисловые например, строковые ключи.
Не говоря уже о том, что pairs
(через next
a>) также выполняет итерацию в неопределенном порядке, тогда как ipairs
всегда будет выполнять итерацию предсказуемым образом от 1
до первого целочисленного ключа, отсутствующего в таблице. Обратите внимание, что если вы используете стандартный цикл for i
с оператором длины #t
< /a>, это может быть немного по-другому, если ваша таблица не является последовательной.
Если не задан метаметод __len, длина таблицы t определяется только в том случае, если таблица представляет собой последовательность, то есть набор ее положительных числовых ключей равен {1..n} для некоторого целого числа n. В этом случае n — его длина.
Во-вторых, установка числовых индексов таблицы, подобной массиву, оставит вашу таблицу с дырами.
local t = {1, 2, 3}
t[2] = nil
-- t is {1, nil, 3}, not {1, 3} as one might expect.
Вам нужно будет использовать table.remove
, если вы хотите сохранить последовательная согласованность вашей таблицы.
local t = {1, 2, 3}
table.remove(t, 2)
-- t is {1, 3}
И последнее, но не менее важное — это менее очевидный и менее интуитивный недостаток в вашем подходе к удалению элементов.
local t = {2, 3, 5, 2, 1}
for i=1, #t do
if t[i] % 2 == 1 then -- If value is odd,
table.remove(t, i) -- remove it.
end
end
-- t is {2, 3, 2}, but that can't be right.
Вы удаляете элементы из массива, перебирая их в прямом порядке. Это неизбежно приведет к тому, что вы пропустите каждый элемент после удаленного, возможно, до точки, где вы перебираете внешнюю часть массива.
Если вы хотите удалить элементы из массива по мере его повторения, вы должны сделать это назад. Если по какой-то причине вы не можете выполнить итерацию по массиву в обратном направлении, вам придется сохранить список индексов, чтобы удалить их позже, и выполнить итерацию по ним в обратном порядке.
В этот момент вы можете спросить: «Почему назад?». Проще говоря, это потому, что цикл не обновляет длину или не сохраняет итератор таким же, как размер таблицы уменьшается, что вызывает пропуск. Если вы пойдете назад, вы сохраните структуру, в которой обрабатывается итерация. Длину не нужно обновлять, поскольку теперь она является начальным значением, а не конечным условием. Итератор не нужно «сдерживать» или удерживать от шага, поскольку перед ним всегда будет больше элементов из-за того, что он движется назад.
local t = {2, 3, 5, 2, 1}
for i=#t, 1, -1 do -- Start at the end and go backwards.
if t[i] % 2 == 1 then
table.remove(t, i)
end
end
-- t is {2, 2}, as expected.
В заключение (версия tl;dr)
- Используйте
ipairs
вместо pairs
для массивов, если вы предпочитаете использовать итераторы вместо цикла for i
.
- Используйте
table.remove
для сохранения последовательности массива.
- Используйте обратные циклы
for i
при удалении элементов из массивов.
person
Ryan Stein
schedule
04.12.2013