@nevro
не пойми кто

Как перебрать массив строк?

Есть массив строк, нужно обратиться к каждой и прочитать посимвольно:
lines = {
       "sdss",
       "vfbf"
      }
for i=1,#lines do
   line = lines[i]
   for j=1, #line do print(line[j]) end
end

Вопросы:
1. Можно ли на lua сделать изящнее?
2. Этот код 8 раз выводит nil, хотя должны быть символы. Что я сделал не так?

P.S. делал в https://www.lua.org/cgi-bin/demo
  • Вопрос задан
  • 614 просмотров
Решения вопроса 2
bitniks
@bitniks
Go/PHP/Symfony developer
for i = 1, #lines do
   line = lines[i]
   for j = 1, #line do 
     print(string.sub(line, j, j))
   end
end

https://rextester.com/VKJ93178
Ответ написан
dollar
@dollar Куратор тега Lua
Делай добро и бросай его в воду.
1) А что вам важнее, изящество или скорость?
1.а) Во-первых, изящнее использовать встроенную функцию ipairs, которая как раз интерирует индексный массив:
lines = {"sdss", "vfbf"}
for i, line in ipairs(lines) do
  print(line)
end

Это изящнее, чем просто обращение по индексу, потому что исчезает строка создания переменной line, она задаётся в самом цикле. Однако с точки зрения производительности такой способ медленнее, потому что конструкции языка быстрее, чем обращение к функциям, даже встроенным. Так что если у вас миллиарды строк, то лучше ваш вариант, хоть он и менее изящен.

1.б) Во-вторых, в вашем примере создаётся переменная line глобально. Это не ошибка, но может привести к ошибке в будущем, если код будет сложный. Поэтому делать так совсем не изящно. Лучше писать так:
local line = lines[i]
Это создаст локальную переменную внутри цикла. Она не будет доступна вне цикла. А если есть одноименная глобальная переменная, то с ней ничего не произойдет. Везде, где только можно, лучше использовать слово local, оно ограничивает область видимости переменной текущим блоком (и вложенными блоками).

Кстати, массив lines тоже желательно задавать через local, если ваш скрипт не рассчитан на несколько файлов и общее глобальное пространство имен между ними. Дело в том, что такие локально-глобальные переменные в пределах файла чуть быстрее, чем классические глобальные.

2) nil выводит потому, что строки в lua не являются итерируемыми объектами, в отличие от строк в javascript, например. То есть строка является объектом, поэтому обращение к свойству [j] не является синтаксической ошибкой, но свойства такого у строки нет, поэтому line[j] возвращает nil.

Обращение к символу в Lua происходит через функцию подстроки:
line:sub[j,j]
То есть мы буквально вырезаем подстроку с позиции j до позиции j, это и есть один символ.

Опять же, красиво создавать локальные переменные, чтобы читателю вашего кода было понятно, что происходит, а потом их использовать. Желательно с комментариями. Например, так:
local c = line:sub[j,j] --Получаем символ с номером j
print(c) --Выводим символ


3) Ну и, наконец, если вам не важна скорость и производительность совсем, а под изяществом вы понимаете как можно более короткую (и/или сложную для понимания) запись кода, то вам подойдёт что-то вроде этого:
Пример
lines = {
  "sdss",
  "vfbf",
}

for i,line in ipairs(lines) do
  for c in line:gmatch"." do
    print(c)
  end
end
Пример 2
lines = {
  "sdss",
  "vfbf",
}

for i,line in ipairs(lines) do
  line:gsub(".",function(c)
    print(c)
  end)
end

Ведь в Lua использовать в качестве итератора любую функцию, кроме pairs и ipairs, очень необычно, не всем понятно, зато "изящно" (если это можно так назвать). Передавать функции в качестве аргументов другой функции - приём также чуть сложнее, чем просто цикл. Ну и регулярные выражения, само собой разумеется, отдельная сложная тема. Тем более, что в Lua регулярки немного иначе устроены, то есть ещё +10% к сложности.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы