In lua, how to do the function of a-b while a & b are arrays or tables
i am a new programmer and started with lua . i want to do the function that array a -b , the following are my program, it didn't work well
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
if a[i]~= nil then
retrun a[i]
end
end
end
end
a = {10, 20, 30}
b={11,20,122}
for element in delTwo (a ,b) do
print(element)
end
I have two questions, the first is input:16: '=' 开发者_开发知识库expected near 'a' retrun a[i] Y should i changed into retrun =a[i] and what is the differences between them
the second is input:3: attempt to get length of local 'a' (a nil value) what is wrong with this, even if i changed into local lengthA = table.getn(a) there will be input:3: bad argument #1 to 'getn' (table expected, got nil)
The first problem was already answered, but regarding the second it just means that a
at some point of your program execution is nil
(== null
). I was not able to repeat this with your example though.
I am not completely certain what you are trying to achieve, but I recommend that you first create a function that creates a new table that stores the desired result and then iterate that using pairs
(or normal looping). Something like the following:
function delTwo(a, b)
local result = {}
--# Logic here.
--# Use result[#result + 1] = ... to insert values.
return result
end
for k, v in pairs(delTwo(a,b)) do print(k, v) end
First of all, your indentation is disguising a problem
with your balance between for
s and end
s.
What you have is:
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
Also, because you are modifying a
inside the loop, its length
becomes smaller and you'll end up accessing it with an invalid index.
Then there's how you use delTwo
's return value.
Here is an explanation on how iterators work in Lua: http://lua-users.org/wiki/IteratorsTutorial
When you write something like for i in <expr>
, <expr>
must return
three values: an iterator function, a state object, and an initial value.
Every iteration, the iterator function will be called with the state object
and the current value (starting with the initial value in <expr>
).
If it returns nil
, the iteration stops, otherwise its return values
are assigned to your loop variables, the body of the for
loop is executed,
and the iterator function will be called again with the same state object and
the new current value, which is the first of your loop variables
(i
in this case).
A (relatively) simple example may help you understand:
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 comes with two iterator generator functions: ipairs
and pairs
.
They both take a table and return what is needed for a for
loop to iterate
over the values stored in that table.
ipairs
expects a table with numeric keys from 1 to #table
and
generates an iterator which will iterate over those indices in order,
returning every time the index and the value:
for i, v in ipairs( { 10, 20, 30 } ) do
print("["..i.."] = " .. v)
end
--// Prints:
--// [1] = 10
--// [2] = 20
--// [3] = 30
pairs
takes any kind of table and generates an iterator which returns pairs of
key and value, with pairs coming in any order.
In this case keys can be anything except nil
, even tables!
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
So, you have two approaches here.
If you want delTwo
to return a table, you must write your for
loop like this:
for idx, element in ipairs(delTwo(a, b)) do
print(element)
end
--// delTwo *must* return a table with correct numeric indices
or like this:
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.
Here's something for you to study. It's a big piece of code, but I hope you can understand it and learn something from 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
This post stands as a testament to how much free time I have in my hands :)
An alternate version which uses metatables
local mt = { --// Just creates a metatable base
__sub = function (a, b) --// Function is the same as Zecc just formatted differently
local lengthB = #b
for j = 1, lengthB do
local lengthA = #a
for i = 1, lengthA do
if a[i] == b[j] then table.remove(a, i) end
end
end
return a
end
}
a = {10, 20, 30} --// Same arrays
b = {11, 20, 122}
setmetatable(a, mt) -- //Use this to give the arrays the __sub function
setmetatable(b, mt)
c = a - b --// Then you can use the maths operator on it
for k, v in ipairs(c) do --// printing them out gives the same as above
print(k, v)
end
Then if you wanted to use different arrays in the same way, just use the setmetatable(x, mt)
where x is the table you want to have the function and it should work.
The problem is like set difference, the following function prepare a dict of possible values to remove from the array b, and check if the array a contain it while traversing. The function has an optional inplace flag if change make in place of the array a or return a new one.
function arrayDiff(a,b,inplace)
inplace = inplace~=false -- default inplace
local ret = inplace and a or {}
local toRemove = {} -- a dict for value to remove
for i=1,#b do toRemove[b[i]]=true end
local nxtInsert = 0
local aLen = #a
for i=1,aLen do
local value = a[i]
if not toRemove[value] then
nxtInsert = nxtInsert + 1
ret[nxtInsert] = value
end
end
if inplace then
for i=nxtInsert+1,aLen do ret[i]=nil end
end
return ret
end
Below is my implementation of your function which does the following: 1. subtract from element x in A, element y from B ( If y exists )
function arrDel(a,b)
local result = {}
for i = 1, #a, 1 do
result[i] = a[i] - ( b[i] or 0) -- 'or 0' exists to cope with if #b < #a
end
return result
end
This code creates and populates a table called result which is the 'result' of subtracting b from a. In lua there exists two types of for loop: the numeric and the generic. The loop in the above function utilizes the numeric type of loop. This loop should be used either when the the block of code it contains needs to be executed a known number of times OR indexing to find the value which the loop uses is trivial.
The sytanx is as follows:
for counter = initial, final, increment do
body
end
The increment is optional, by default it is 1.
To demonstrate the other type of loop this small function prints out a very simple table:
function tprint(t)
local res = {}
for _,v in ipairs(t) do
res[#res+1] = v
end
print("{"..table.concat(res,",").."}")
end
Here the generic for is used ( the 'in' keyword is used ). The generic for allows easy traversal of complex objects. For instance, say an object contained records of users, however the records were stored in sections i.e VIP, Administrator, Guest, etc... And you wanted to go over ALL the users. You can write a function which you then use in the generic for to do this easily with an expression similar to this:
for user in object.traverseUsers() do
body
end
The implementation of such iterators is beyond the scope of an answer to this question, but a great explanation can be found here Generic For (PIL)
- You spelled "return" as "retrun".
If there is that possibility that something other than a table would be given but you still want to keep the code running, use this
local lengthA = a and #a or 0 local lengthB = b and #b or 0
Not really necessary, but just a little info; No need to say
if a[i] ~= nil then
You can just do this instead:
if a then
精彩评论