문제

최근에 나는 LUA 코드를 약간 썼습니다.

local a = {}
for i = 1, n do
   local copy = a
   -- alter the values in the copy
end

분명히, 변수는 LUA의 테이블 자체가 아닌 익명 테이블에 대한 참조를 가지고 있기 때문에 내가하고 싶었던 일이 아니 었습니다. 이것은 명확하게 배치되어 있습니다 LUA의 프로그래밍, 그러나 나는 그것에 대해 잊었습니다.

그래서 질문은 내가 대신 무엇을 써야하는지입니다. copy = a 값의 사본을 얻으려면 a?

도움이 되었습니까?

해결책

약간 읽기 쉬운 코드 골프를 재생하려면 표준 까다로운 케이스를 처리하는 짧은 버전이 있습니다.

  • 키로 테이블,
  • 메타 타이블 보존 및
  • 재귀 테이블.

우리는 이것을 7 줄로 할 수 있습니다.

function copy(obj, seen)
  if type(obj) ~= 'table' then return obj end
  if seen and seen[obj] then return seen[obj] end
  local s = seen or {}
  local res = setmetatable({}, getmetatable(obj))
  s[obj] = res
  for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end
  return res
end

LUA Deep-Copy 운영에 대한 짧은 글이 있습니다. 이 요점.

또 다른 유용한 참조입니다 이 lua-users 위키 페이지, 여기에는 피하는 방법에 대한 예가 포함됩니다. __pairs 메타 메드.

다른 팁

테이블 사본에는 많은 잠재적 인 정의가 있습니다. 간단하거나 딥 카피를 원하는지 여부, 메타 타이블을 복사, 공유 또는 무시하려는 것인지 등 모든 사람을 만족시킬 수있는 단일 구현은 없습니다.

한 가지 방법은 단순히 새 테이블을 만들고 모든 키/값 쌍을 복제하는 것입니다.

function table.shallow_copy(t)
  local t2 = {}
  for k,v in pairs(t) do
    t2[k] = v
  end
  return t2
end

copy = table.shallow_copy(a)

사용해야합니다 pairs 대신에 ipairs, 부터 ipairs 테이블 키의 하위 집합에 대해서만 반복하십시오 (예 : 순서가 높아지면서 연속적인 양의 정수 키).

요점을 설명하기 위해 내 개인 table.copy 또한 메타 타블에주의를 기울입니다.

function table.copy(t)
  local u = { }
  for k, v in pairs(t) do u[k] = v end
  return setmetatable(u, getmetatable(t))
end

"표준"이라고 불리기 위해 충분히 널리 동의 한 사본 함수는 없습니다.

딥 카피의 정식 버전, 3 가지 상황을 모두 처리합니다.

  1. 테이블 원형 참조
  2. 테이블이기도하는 키
  3. 중단

일반 버전 :

local function deepcopy(o, seen)
  seen = seen or {}
  if o == nil then return nil end
  if seen[o] then return seen[o] end

  local no
  if type(o) == 'table' then
    no = {}
    seen[o] = no

    for k, v in next, o, nil do
      no[deepcopy(k, seen)] = deepcopy(v, seen)
    end
    setmetatable(no, deepcopy(getmetatable(o), seen))
  else -- number, string, boolean, etc
    no = o
  end
  return no
end

또는 테이블 버전 :

function table.deepcopy(o, seen)
  seen = seen or {}
  if o == nil then return nil end
  if seen[o] then return seen[o] end


  local no = {}
  seen[o] = no
  setmetatable(no, deepcopy(getmetatable(o), seen))

  for k, v in next, o, nil do
    k = (type(k) == 'table') and k:deepcopy(seen) or k
    v = (type(v) == 'table') and v:deepcopy(seen) or v
    no[k] = v
  end
  return no
end

를 기반으로 lua-users.org/wiki/copytable'모래 앨런 예이츠'기능.

선택적으로 깊고 그래프 글로벌 재귀 버전 :

function table.copy(t, deep, seen)
    seen = seen or {}
    if t == nil then return nil end
    if seen[t] then return seen[t] end

    local nt = {}
    for k, v in pairs(t) do
        if deep and type(v) == 'table' then
            nt[k] = table.copy(v, deep, seen)
        else
            nt[k] = v
        end
    end
    setmetatable(nt, table.copy(getmetatable(t), deep, seen))
    seen[t] = nt
    return nt
end

아마도 무의미한 사본도 선택 사항이어야합니까?

내가 실제로 한 일은 다음과 같습니다.

for j,x in ipairs(a) do copy[j] = x end

처럼 의심은 언급합니다, 테이블 키가 엄격하게 단조롭게 증가하지 않으면 pairs ~ 아니다 ipairs.

나는 또한 a를 찾았다 deepcopy 더 강력한 함수 :

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

재귀 적으로 부르면서 테이블과 메타 테이블을 처리합니다.그것은 그 자체의 보상입니다). 영리한 비트 중 하나는 모든 값 (테이블이든 아니든)를 전달할 수 있으며 올바르게 복사됩니다. 그러나 비용은 스택을 지나치게 넘어 질 수 있다는 것입니다. 그래서 더욱 강력한 (비 수상자) 기능 필요할 수 있습니다.

그러나 이것은 배열을 다른 변수로 복사하려는 매우 간단한 경우에 과잉입니다.

(불행히도 가볍게 문서화) stdlib 프로젝트에는 표준 LUA 배포판이 포함 된 여러 라이브러리에 대한 여러 가지 소중한 확장이 있습니다. 그중에는 테이블 복사 및 병합 주제에 대한 몇 가지 변형이 있습니다.

이 라이브러리도 포함되어 있습니다 Windows 용 Lua 배포, 아마도 심각한 LUA 사용자의 도구 상자의 일부일 것입니다.

손으로 이런 것들을 구현할 때 확인해야 할 한 가지는 메타 타이블의 적절한 취급입니다. 간단한 테이블 구조 응용 프로그램의 경우 메타 타이블이없고 사용하는 간단한 루프가 없을 것입니다. pairs() 허용되는 대답입니다. 그러나 테이블이 나무로 사용되거나 원형 참조가 포함되어 있거나 메타 타이블이있는 경우 상황이 더 복잡해집니다.

함수도 참조라는 것을 잊지 마십시오. 따라서 별도의 함수를 가져 오는 데 필요한 모든 값을 완전히 '복사'하려는 경우. 그러나 기능을 복사하는 유일한 방법은 사용하는 것입니다. loadstring(string.dump(func)), LUA 참조 매뉴얼에 따르면 UPVALUES가있는 함수에는 효과가 없습니다.

do
    local function table_copy (tbl)
        local new_tbl = {}
        for key,value in pairs(tbl) do
            local value_type = type(value)
            local new_value
            if value_type == "function" then
                new_value = loadstring(string.dump(value))
                -- Problems may occur if the function has upvalues.
            elseif value_type == "table" then
                new_value = table_copy(value)
            else
                new_value = value
            end
            new_tbl[key] = new_value
        end
        return new_tbl
    end
    table.copy = table_copy
end

경고 : 표시된 솔루션은입니다 잘못된!

테이블에 테이블이 포함 된 경우 해당 테이블에 대한 참조는 여전히 사용됩니다. 나는 위의 코드를 사용했기 때문에 내가 저지른 실수를 위해 2 시간을 찾고 있습니다.

따라서 값이 테이블인지 아닌지 확인해야합니다. 그렇다면, 당신은 Table.copy를 재귀 적으로 호출해야합니다!

이것은 올바른 테이블입니다. 코피 함수 :

function table.copy(t)
  local t2 = {};
  for k,v in pairs(t) do
    if type(v) == "table" then
        t2[k] = table.copy(v);
    else
        t2[k] = v;
    end
  end
  return t2;
end

참고 : 테이블에 기능이나 다른 특수 유형이 포함되어있을 때 불완전 할 수도 있지만 대부분의 사람들이 필요로하지 않는 것입니다. 위의 코드는 필요한 사람들에게 쉽게 적응할 수 있습니다.

기본 테이블에 대해 얻는 것만 큼 좋습니다. 메타 타이블로 테이블을 복사 해야하는 경우 DeepCopy와 같은 것을 사용하십시오.

LUA가 표준 라이브러리에 'table.copy ()'가없는 이유는 작업이 정의하는 것이 정확하지 않기 때문입니다. 이미 여기에 표시된 바와 같이, 사본을 "원 레벨 깊이"(당신이 한)를 만들 수 있으며, 중복 참조가 있거나없는 심해를 만들 수 있습니다. 그리고 메타 타이블이 있습니다.

개인적으로, 나는 여전히 내장 기능을 제공하기를 원합니다. 사람들이 의미론에 만족하지 않는 경우에만 스스로해야 할 것입니다. 그러나 종종 실제로는 사본 별 요구가 있습니다.

테이블을 복사해야 할 경우 대부분의 경우 원래 테이블의 수정이 사본에 영향을 미치지 않도록 원본과 아무것도 공유하지 않는 사본을 갖고 싶었습니다.

지금까지 보여지는 모든 스 니펫은 원래 테이블을 가리키는 테이블을 공유 할 수있는 테이블에 대한 사본을 만드는 데 실패합니다. 생성 된 테이블을 다음과 같이 복사하려고하는지 쉽게 알 수 있습니다. a = {}; a[a] = a. 심해 Jon이 언급 한 기능은이를 처리하므로 실제/전체 사본을 만들어야하는 경우, deepcopy 사용되어야한다.

여기에서 Penlight 라이브러리를 사용하십시오.https://stevedonovan.github.io/penlight/api/libraries/pl.tablex.html#deepcopy

local pl = require 'pl.import_into'()
local newTable = pl.tablex.deepcopy(oldTable)

이것은 가장 간단한 방법 일 수 있습니다.

local data = {DIN1 = "Input(z)", DIN2 = "Input(y)", AINA1 = "Input(x)"}

function table.copy(mytable)  --mytable = the table you need to copy

    newtable = {}

    for k,v in pairs(mytable) do
        newtable[k] = v
    end
    return newtable
end

new_table = table.copy(data)  --copys the table "data"

내 상황에서 테이블의 정보가 데이터 및 기타 테이블 (함수 제외) 인 경우 다음 코드 라인입니다.

local copyOfTable = json.decode( json.encode( sourceTable ) )

나는 Fibaro 홈 센터에서 일부 홈 자동화에 대한 LUA 코드를 작성하고 있습니다. LUA의 구현은 참조 할 수있는 중앙 기능 라이브러리가 없으면 매우 제한적입니다. 코드를 서비스 할 수 있도록 모든 기능을 코드에 선언해야하므로 이와 같은 한 줄의 솔루션이 유리합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top