В lua, как сделать функцию ab, в то время как a & b являются массивами или таблицами - PullRequest
0 голосов
/ 28 октября 2010

Я новый программист и начал с Луа. я хочу сделать функцию, которая массив -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' retrun a [i] Y если я изменился на retrun = a [i] и в чем разница между ними

второй ввод: 3: попытка получить длину локального «а» (нулевое значение) что не так с этим, даже если я изменил на локальную длину A = table.getn (a) будет ввод: 3: неверный аргумент # 1 для 'getn' (таблица ожидалась, получена ноль)

Ответы [ 6 ]

2 голосов
/ 02 ноября 2010

Прежде всего, ваш отступ маскирует проблему с вашим балансом между 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

Этот пост свидетельствует о том, сколько свободного времени у меня в руках:)

2 голосов
/ 28 октября 2010

Первая проблема уже была решена, но в отношении второй это просто означает, что 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 голос
/ 01 августа 2017

Проблема как заданная разница, следующая функция подготавливает указание возможных значений для удаления из массива b и проверяет, содержит ли массив a его при прохождении.Функция имеет необязательный флаг inplace, если изменение производится вместо массива a или возвращает новый.

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
1 голос
/ 10 ноября 2010

Альтернативная версия, в которой используются метатаблицы

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 - это таблица, в которой вы хотите использовать функцию, и она должна работать.

0 голосов
/ 15 марта 2017
  1. Вы записали "return" как "retrun".
  2. Если существует такая вероятность, что будет предоставлено что-то, кроме таблицы, но вы все равно хотите сохранить работоспособность кода, используйте это

    local lengthA = a and #a or 0
    local lengthB = b and #b or 0
    
  3. Не совсем необходимо, но немного информации; Не нужно говорить

       if a[i] ~= nil then
    

Вы можете просто сделать это вместо:

    if a then
0 голосов
/ 21 апреля 2013

Ниже приведена моя реализация вашей функции, которая выполняет следующие действия: 1. вычитает из элемента x в A элемент y из B (если 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

Этот код создает и заполняет таблицу с именемрезультат, который является «результатом» вычитания b из a.В 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

Здесь используется общий для (используется ключевое слово in).Универсальный для позволяет легко обходить сложные объекты.Например, скажем, объект содержал записи пользователей, однако записи хранились в разделах, таких как VIP, Администратор, Гость и т. Д. И вы хотели просмотреть ВСЕХ пользователей.Вы можете написать функцию, которую затем будете использовать в обобщенном выражении, чтобы сделать это легко с помощью выражения, подобного следующему:

for user in object.traverseUsers() do
  body
end

Реализация таких итераторов выходит за рамки ответа на этот вопрос, ноотличное объяснение можно найти здесь Generic For (PIL)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...