Прежде всего, ваш отступы маскировать проблему с баланса между 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
«s.
Вот объяснение того, как итераторы работают в Lua: http://lua-users.org/wiki/IteratorsTutorial
Когда вы пишете что-то вроде for i in <expr>
, <expr>
должен вернуть три значения: функцию итератор, состояние объекта, и начальное значение.
Каждая итерация, функция итератора будет вызываться с объектом состояния и текущим значением (начиная с начального значения в <expr>
). Если она возвращает nil
, итерация останавливается, в противном случае возвращаемых значений назначена ваш переменный цикл, тело цикла for
выполняется, и функция итератора будет вызываться снова с тем же состоянием объектом и новой текущими значение, которое является первым из ваших переменных цикла (i
в этом случае).
A (относительно) простой пример может помочь вам понять:
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
Этот пост является свидетельством того, сколько свободного времени у меня в руках :)
Я не знаю, очень хорошо, но относительно вашей первой ошибки: действительно ли ваш код говорит «retrun a [i]'? Если это так, то я предполагаю, что вы хотели набрать 'return'. Интерпретатор lua предполагает, что 'retrun' - это локальная переменная, так как не распознает его как допустимое ключевое слово, поэтому ожидает инициализации задания. – eldarerathis
спасибо, u решить мою первую проблему, я все еще работаю со вторым – workfor3days
Я не понимаю, каков ожидаемый результат delTwo. Можете ли вы написать ожидаемый результат своей программы? – kikito