在lua中,如何在a&b中执行a-b的功能。 b是数组或表

时间:2010-10-28 04:35:49

标签: lua

我是一名新程序员并以lua开始。我想做数组a -b的功能,以下是我的程序,它运行不正常

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

我有两个问题,第一个是输入:16:'='预计在'a'附近   后退a [i] Y我应该改成retrun = a [i] 他们之间有什么区别

第二个输入:3:尝试获取本地'a'的长度(零值) 这有什么问题,即使我改成了本地长度A = table.getn(a) 将有输入:3:错误的参数#1到'getn'(表格预期,得到零)

6 个答案:

答案 0 :(得分:2)

第一个问题已经得到解答,但就第二个问题而言,这只意味着a在程序执行的某个时刻nil(== null)。不过,我无法用你的例子重复这个。

我不完全确定您要实现的目标,但我建议您首先创建一个函数,创建一个存储所需结果的新表,然后使用pairs(或正常循环)进行迭代。如下所示:

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

答案 1 :(得分:2)

首先,你的缩进是在掩盖一个问题 在forend s之间保持平衡。

你拥有的是:

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/wiki/IteratorsTutorial

当你写for i in <expr>之类的内容时,<expr>必须返回 三个值:迭代器函数,状态对象和初始值。

每次迭代时,都会使用state对象调用迭代器函数 和当前值(从<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带有两个迭代器生成器函数:ipairspairs。 它们都采用表格并返回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

这篇文章证明了我手中有多少空闲时间:)

答案 2 :(得分:1)

使用元表的替代版本

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

然后,如果你想以相同的方式使用不同的数组,只需使用setmetatable(x, mt),其中x是你想拥有该函数的表,它应该可以工作。

答案 3 :(得分:1)

问题就像设置差异一样,下面的函数准备一个可能值的dict从数组b中删除,并在遍历时检查数组a是否包含它。如果更改make代替数组a或返回一个新的,则该函数具有可选的inplace标志。

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

答案 4 :(得分:0)

以下是我的函数实现,它执行以下操作:  1.从A中的元素x中减去,从B中减去元素y(如果y存在)

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

此代码创建并填充一个名为result的表,该表是从a中减去b的“结果”。在lua中存在两种类型的for循环:数字和泛型。上述函数中的循环使用数字类型的循环。当它包含的代码块需要执行已知次数或索引以找到循环使用的值是微不足道时,应该使用此循环。

sytanx如下:

for counter = initial, final, increment do
  body
end

增量是可选的,默认为1。


为了演示另一种类型的循环,这个小函数打印出一个非常简单的表:

function tprint(t)
    local res = {}
    for _,v in ipairs(t) do
       res[#res+1] = v
    end
    print("{"..table.concat(res,",").."}")
end

此处使用泛型for(使用'in'关键字)。通用允许轻松遍历复杂对象。例如,假设一个对象包含用户的记录,但是记录存储在VIP,管理员,访客等部分中......并且您想要覆盖所有用户。您可以编写一个函数,然后在泛型中使用该函数,使用类似于此的表达式轻松完成此操作:

for user in object.traverseUsers() do
  body
end

这些迭代器的实现超出了这个问题的答案范围,但可以在这里找到一个很好的解释Generic For (PIL)

答案 5 :(得分:0)

  1. 你拼写了#34;返回&#34; as&#34; retrun&#34;。
  2. 如果有可能会给出除表之外的其他内容,但您仍希望保持代码运行,请使用此

    local lengthA = a and #a or 0
    local lengthB = b and #b or 0
    
  3. 不是必需的,只是一点信息;无需说

       if a[i] ~= nil then
    
  4. 你可以这样做:

        if a then