1 (31.01.2014 21:50:38 отредактировано xxblx)

Всем доброго времени суток.
В Lua есть две удобные вещи: pairs и ipairs, предназначенные для использования с таблицами.
pairs для таблиц - ассоциативных массивов (ключ - значение). Точнее сказать, pairs обычно используется с ассоциативными массивами, но и с обычными таблицами-массивами тоже работает.
ipairs для таблиц - обычных массивов (упорядоченные элементы с последовательными индексами от 1 до <количество_элементов_таблицы>). По сути, разница (относительно pairs) в том, что ключ  "целочисленный", начинается с единицы и по возрастающей с шагом 1.

for i, v in pairs(t) do
  print(i) -- выдаст ключ
  print(v) -- выдаст значение
end
> t = { ["A"] = "a", ["B"] = "b", ["C"] = "c"}
> for i, v in pairs(t) do
>> print(i)
>> print(v)
>> end
B
b
C
c
A
a
for i, v in ipairs(t) do
  print(i) -- выдаст индекс элемента
  print(v) -- выдаст сам элемент
end
> t = { "a", "b", "c", "d" }
> for i, v in ipairs(t) do
>> print(i)
>> print(v)
>> end
1
a
2
b
3
c
4
d

Все вроде бы понятно. Но, как обычно и бывает, способ написанный в документации - не единственный. И чтобы обойти таблицу-массив можно воспользоваться другим вариантом:

-- #t = длина таблицы t
for i = 1, #t do
   print(t[i]) -- выдаст элемент
end
> for i = 1, #t do
>> print(t[i])
>> end
a
b
c
d

В Lua 5.2 (в других не проверял) если провести сравнительный тест, то становится наглядно видно, чтобы цикла вида for i = 1, #t отрабатывает раза в 1.5-2 быстрее, чем for i, v in ipairs(t).
Откуда берется разница - вроде понятно, for i = 1, #t просто перебирает i с шагом 1, а for i, v in ipairs(t) именно получает значение и индекса, и элемента, по тому и отрабатывает медленней.

Вопрос в следующем, на какие подводные камни можно наткнутся, если использовать for i = 1, #t для обхода таблицы-массива вместо for i, v in ipairs(t). По тому что хоть for i, v in ipairs(t) вроде и правильней, жертвовать скоростью совсем не хочется.
Понятно, что если в цикле предстоит удалять элементы, то for i = 1, #t использовать нельзя

-- на момент начала цикла #t - какое-то конкретное значение типа number
for i = 1, #t do
   if (t[i] == "str") then
      -- как только удалим элемент, размер таблицы изменится, 
      -- а значит цикл выйдет за пределы таблицы и будет ошибка
      table.remove(t, i)
   end
end

А помимо удаления и подобных операций, когда таблица в ходе цикла будет заметно изменена, есть еще какие-то ситуации, когда использование for i = 1, #t do чревато проблемами?
И вообще, что посоветуете: не брезгать "быдлокодить" с for i = 1, #t do раз это дает профит по скорости работы, либо же строго придерживаться ipairs() по тому что "так положено" ?

Fedora GNOME3

2

Почитал архив почтовой рассылки Lua. Но до конца так и не понял, то ли ipairs() хотели убрать, но передумали, то ли уберут в следующих версиях. Непонятно.
По-видимому, это уже довод за for i = 1, #table. Код лишний раз переписывать не придется, если ipairs все-таки выпилят ab
Надеюсь, pairs убирать не будут. На ipairs наплевать, а вот без pairs будет неудобно, конечно.

Fedora GNOME3

3

в перле это хеши,
причем работают одинаково быстро для любого количества ключ => значение

так же существуют
массивы
массивы хешей
хеши массивов

"Фирма Майкрософт не собирается поддерживать протокол TCP/IP в своих OS" 1993 (c) Билл Гейтс
"Мы изобрели новый протокол передачи данных, мы назвали его TCP/IP" 1995 (c) Билл Гейтс