63

最近、次のような Lua コードを少し書きました。

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

変数は、Lua のテーブル自体の値ではなく、匿名テーブルへの参照を保持するため、明らかに、それは私がやりたかったことではありません。これはProgramming in Luaで明確に説明されていますが、忘れていました。

問題はcopy = a、値のコピーを取得する代わりに、何を書くべきかということaです。

4

15 に答える 15

49

テーブル コピーには、多くの潜在的な定義があります。それは、単純なコピーが必要かディープ コピーが必要か、メタテーブルをコピー、共有、または無視するかどうかなどによって異なります。すべての人を満足させる単一の実装はありません。

1 つの方法は、単純に新しいテーブルを作成し、すべてのキーと値のペアを複製することです。

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の代わりにを使用する必要があることに注意してください。これは、テーブル キーのサブセット (つまり、昇順で 1 から始まる連続した正の整数キー) に対してのみ反復処理を行うためですipairsipairs

于 2009-03-13T09:51:30.167 に答える
32

要点を説明するために、私は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

「標準」と呼ばれるほど広く合意されているコピー機能はありません。

于 2009-03-20T00:56:28.750 に答える
10

必要に応じて、深いグラフ一般の再帰バージョン:

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

おそらく、メタ可能なコピーもオプションである必要がありますか?

于 2011-04-19T01:17:52.790 に答える
7

これが私が実際にしたことです:

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

Doubが言及しているように、テーブル キーが厳密に単調に増加していない場合は、そうではpairsないはずipairsです。

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

テーブルとメタテーブルを再帰的に呼び出すことで処理します (これは独自の報酬です)。巧妙なビットの 1 つは、任意の値 (テーブルであるかどうかにかかわらず) を渡すことができ、正しくコピーされることです。ただし、代償として、スタックがオーバーフローする可能性があります。そのため、さらに堅牢な (非再帰的)関数が必要になる場合があります。

しかし、配列を別の変数にコピーしたいという非常に単純なケースでは、それはやり過ぎです。

于 2009-03-12T21:52:19.613 に答える
4

(残念ながら文書化が少ない) stdlibプロジェクトには、標準の Lua ディストリビューションに同梱されているいくつかのライブラリに対する多くの価値ある拡張機能があります。その中には、テーブルのコピーとマージをテーマにしたいくつかのバリエーションがあります。

このライブラリはLua for Windowsディストリビューションにも含まれており、本格的な Lua ユーザーのツールボックスの一部になっているはずです。

このようなものを手動で実装する際に確認すべきことの 1 つは、メタテーブルを適切に処理することです。構造としての単純なテーブル アプリケーションの場合、おそらくメタテーブルはなく、使用する単純なループpairs()は受け入れられる答えです。しかし、テーブルがツリーとして使用されたり、循環参照が含まれていたり、メタテーブルが含まれていたりすると、事態はさらに複雑になります。

于 2009-03-13T21:19:37.547 に答える
2

Lua の標準ライブラリに「table.copy()」がない理由は、タスクを正確に定義できないためだと思います。すでにここで示したように、「1 レベルの深さ」のコピーを作成する (実際に行った)、重複参照の可能性を考慮して、または考慮せずにディープコピーを作成できます。そして、メタテーブルがあります。

個人的には、組み込み機能を提供してほしいと思っています。人々がそのセマンティクスに満足しない場合にのみ、自分でやる必要があります。ただし、実際に値によるコピーが必要になることはあまりありません。

于 2009-03-15T23:05:28.347 に答える
1

ほとんどの場合、テーブルをコピーする必要があるときは、元のテーブルを変更してもコピーに影響がないように(またはその逆)、元のテーブルと何も共有しないコピーが必要でした。

これまでに示したすべてのスニペットは、共有キーまたはテーブルとのキーを持っている可能性のあるテーブルのコピーを作成できません。これらは元のテーブルを指しているままになります。次のように作成されたテーブルをコピーしようとすると、簡単に確認できますa = {}; a[a] = aJonが参照するdeepcopy関数がそれを処理するため、実際の/完全なコピーを作成する必要がある場合は、を使用する必要がありますdeepcopy

于 2012-06-10T22:20:40.393 に答える
1

これは、基本的なテーブルで得られるものと同じです。メタテーブルを含むテーブルをコピーする必要がある場合は、deepcopy などを使用します。

于 2009-03-13T00:48:21.143 に答える
1

ここでペンライト ライブラリを使用します: https://stevedonovan.github.io/Penlight/api/libraries/pl.tablex.html#deepcopy

local pl = require 'pl.import_into'()
local newTable = pl.tablex.deepcopy(oldTable)
于 2016-01-31T18:29:53.863 に答える
0

これは最も簡単な方法かもしれません:

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"
于 2015-06-22T14:24:09.993 に答える