首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在lua中,当a&b是数组或表时,如何做a-b的函数

在lua中,当a&b是数组或表时,如何做a-b的函数
EN

Stack Overflow用户
提问于 2010-10-28 12:35:49
回答 6查看 1.2K关注 0票数 0

我是一个新的程序员,从lua开始。我想做一个数组-b的函数,下面是我的程序,它不能很好地工作

代码语言:javascript
复制
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’retrun ai Y是否应该改为retrun =ai,它们之间的区别是什么

第二个是输入:3:尝试获取本地'a‘( nil值)的长度。这有什么问题,即使我更改为本地lengthA = table.getn (a ),也会有输入:3:'getn’的错误参数#1 (期望的表,得到的是nil)

EN

回答 6

Stack Overflow用户

发布于 2010-10-28 13:41:16

第一个问题已经回答了,但是关于第二个问题,它只是意味着在你的程序执行的某个点上的anil (== null)。不过,我无法在您的示例中重复这一点。

我不能完全确定您想要实现什么,但我建议您首先创建一个函数,该函数创建一个存储所需结果的新表,然后使用pairs (或常规循环)迭代该表。类似于以下内容:

代码语言:javascript
复制
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
票数 2
EN

Stack Overflow用户

发布于 2010-11-02 18:41:34

首先,缩进掩盖了fors和ends之间的平衡问题。

你所拥有的是:

代码语言:javascript
复制
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>必须返回三个值:迭代器函数、状态对象和初始值。

每次迭代时,都会使用状态对象和当前值(从<expr>中的初始值开始)调用迭代器函数。如果返回nil,则迭代停止,否则将其返回值赋给您的循环变量,执行for循环体,并使用相同的状态对象和新的当前值再次调用迭代器函数,当前值是您的第一个循环变量(在本例中为i)。

一个(相对)简单的例子可能会帮助你理解:

代码语言:javascript
复制
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的数字键的表,并生成一个迭代器,该迭代器将按顺序迭代这些索引,每次索引和值都会返回:

代码语言:javascript
复制
for i, v in ipairs( { 10, 20, 30 } ) do
    print("["..i.."] = " .. v)
end
--// Prints:
--//    [1] = 10
--//    [2] = 20
--//    [3] = 30

pairs接受任何类型的表,并生成一个迭代器,该迭代器返回键和值对,其中键和值对以任何顺序出现。在这种情况下,键可以是除了nil之外的任何东西,甚至是表!

代码语言:javascript
复制
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循环:

代码语言:javascript
复制
for idx, element in ipairs(delTwo(a, b)) do
   print(element)
end    
--// delTwo *must* return a table with correct numeric indices

或者像这样:

代码语言:javascript
复制
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.

这里有一些你需要学习的东西。这是一段很大的代码,但我希望你能理解它,并从中学到一些东西。

代码语言:javascript
复制
--//////////////////////////////////////////////////////////////////////////
--//
--// 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
EN

Stack Overflow用户

发布于 2010-11-10 07:01:31

使用元对象的备用版本

代码语言:javascript
复制
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是你想要拥有函数的表,它应该可以工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4039802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档