Прежде всего, ваш отступ маскирует проблему
с вашим балансом между for
с и end
с.
Что у вас есть:
function delTwo (a ,b)
local i = 0
local lengthA = #a
local lengthB = #b
for i = 1, lengthA do
for j = 1, lengthB do
if a[i] == b[j] then
a[i] = nil
end
end
for i = 1, lengthA do --// Iterating i while iterating i. Bad things happen!
if a[i] ~= nil then
return a[i]
end
end
end
end
Кроме того, поскольку вы изменяете a
внутри цикла, его длина
становится меньше, и вы получите доступ к нему с недопустимым индексом.
Тогда вот как вы используете возвращаемое значение delTwo
.
Вот объяснение того, как итераторы работают в Lua:
http://lua -users.org / вики / IteratorsTutorial
Когда вы пишете что-то вроде for i in <expr>
, <expr>
должен возвращаться
три значения: функция итератора, объект состояния и начальное значение.
На каждой итерации функция итератора будет вызываться с объектом состояния
и текущее значение (начиная с начального значения в <expr>
).
Если он возвращает nil
, итерация останавливается, в противном случае ее возвращаемые значения
присваиваются переменным вашего цикла, выполняется тело цикла for
,
и функция итератора будет вызываться снова с тем же объектом состояния и
новое текущее значение, которое является первой из ваших переменных цикла
(i
в данном случае).
(относительно) простой пример может помочь вам понять:
local state = {}
state["toggle"] = true
function iterator_func(state, prev_i)
--// Calculate current value based on previous value
i = prev_i + 1
--// Stop iteration if we've had enough
if i > 10 then
return nil
end
local msg
if state["toggle"] then
msg = "It's on!"
state["toggle"] = false
else
msg = "It's off!"
state["toggle"] = true
end
return i, i*2, i*3, msg
end
--// Notice the initial value is 0, the value *before* our first iteration
for i, double, triple, msg in iterator_func, state, 0 do
print(tostring(i)..", "
..tostring(double)..", "
..tostring(triple)..", "
..tostring(msg))
end
--// Prints:
--// 1, 2, 3, It's on!
--// 2, 4, 6, It's off!
--// ...
--// 10, 20, 30, It's off!
Lua поставляется с двумя функциями генератора итераторов: ipairs
и pairs
.
Они оба берут таблицу и возвращают то, что нужно для цикла for
для итерации
над значениями, хранящимися в этой таблице.
ipairs
ожидает таблицу с цифровыми клавишами от 1 до #table
и
генерирует итератор, который будет перебирать эти индексы по порядку,
возвращая каждый раз индекс и значение:
for i, v in ipairs( { 10, 20, 30 } ) do
print("["..i.."] = " .. v)
end
--// Prints:
--// [1] = 10
--// [2] = 20
--// [3] = 30
pairs
берет таблицу любого типа и генерирует итератор, который возвращает пары
ключ и значение, с парами в любом порядке.
В этом случае ключи могут быть чем угодно, кроме nil
, даже таблиц!
aKey = {}
t = { ["First"] = 10, [2.0] = 20, [aKey] = 30 }
for k, v in pairs(t) do
print("["..tostring(k).."] = " .. tostring(v))
end
--// Prints something like:
--// [table: 0x95860b0] = 30
--// [First] = 10
--// [2] = 20
Итак, у вас есть два подхода здесь.
Если вы хотите, чтобы delTwo
вернул таблицу, вы должны написать свой цикл for
следующим образом:
for idx, element in ipairs(delTwo(a, b)) do
print(element)
end
--// delTwo *must* return a table with correct numeric indices
или как это:
for _, element in pairs(delTwo(a, b)) do
print(element)
end
--// Conventionally, you use _ as a variable name if you plan to just ignore it.
Вот кое-что для изучения.
Это большой кусок кода, но я надеюсь, что вы поймете это и узнаете что-то из него.
--//////////////////////////////////////////////////////////////////////////
--//
--// APPROACH #1
--//
--//
--// This function modifies table a in place,
--// removing elements that are also found in b
--//
local function delTwo_1(a, b)
local lengthB = #b
--// a's length may change if we remove an element from it,
--// so iterate over b and recalculate a's length every iteration.
for j = 1, lengthB do
local lengthA = #a
for i = 1, lengthA do
if a[i] == b[j] then
table.remove(a, i)
--// Don't use " a[i] = nil ".
--// This will just leave you with a nil element in the "middle"
--// of the table, and as it happens ipairs() stops
--// at the first nil index it finds.
--// So:
--// a = { [1] = 10, [2] = 20, [3] = 30}
--// a[2] = nil
--// -- a is now { [1] = 10, [2] = nil, [3] = 30 }.
--//
--// -- ipairs(a) will now return (1, 10) and then stop.
--//
--// -- pairs(a) will return both (1, 10) and (3, 30)
end
end
end
--// Return table a if you want,but it's been modified "outside" as well
return a
end
--//////////////////////////////////////////////////////////////////////////
--//
--// APPROACH #2
--//
--//
--// This function calculates the difference between two tables,
--// without modifying any of them.
--// It will be used in our iterator generator.
--//
local function tableDiff(a, b)
local res = {}
for i = 1, #a do
local skip = false
for j = 1, #b do
if a[i] == b[j] then
skip = true
break
end
end
if not skip then
res[#res+1] = a[i]
end
end
return res
end
--//
--// This function is an iterator generator.
--// It returns an iterator function, a state object and an initial value
--//
local function delTwo_2(a, b)
--// Some preliminary calculations...
local res = tableDiff(a, b)
--// We don't really need state in this case, because we could
--// refer directly to our res variable inside our iterator function,
--// but this is just for demonstration purposes.
local state = {}
state["result"] = res
local function iterator(state, key)
local result = state["result"]
--// Our key is a numeric index, incremented every iteration
--// before anything else (that's just how it works)
key = key + 1
if key > #result then
--// If key is greater than our table length,
--// then we already iterated over all elements.
--// Return nil to terminate.
return nil
end
local element = result[key]
--// Just because we can...
local msg = "We're at element "..key
return key, element, msg
end
local initialKey = 0 --// We start "before" index 1
return iterator, state, initialKey
end
do
--// TESTS
do
--// TESTING APPROACH #1
a = {10, 20, 30}
b = {11, 20, 122}
print "******************* delTwo_1 *******************"
print "Here's delTwo_1's result:"
--// Table a is modified in place
delTwo_1(a, b)
for i, element in ipairs(a) do
print("["..i.."] = "..tostring(element))
end
print()
print "Here's a after delTwo_1:"
for i, element in ipairs(a) do
print("["..i.."] = "..tostring(element))
end
end
print()
print()
do
--// TESTING APPROACH #2
a = {10, 20, 30}
b = {11, 20, 122}
print "******************* delTwo_2 *******************"
print "Here's delTwo_2's result:"
--// Notice how this compares to what
--// is returned by our iterator function
for idx, element, msg in delTwo_2(a, b) do
print(tostring(element) .. " (Msg: "..msg..")")
end
print()
print "Here's a after delTwo_2:"
for i, element in ipairs(a) do
print("["..i.."] = "..tostring(element))
end
end
end
Этот пост свидетельствует о том, сколько свободного времени у меня в руках:)