1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaのテーブルメソッドで安全に要素を削除する

2022-02-10 09:45:09

Luaでは、テーブルから要素を安全に削除する方法を知っておくことが重要です。気をつけないと、間違って削除してしまい、メモリリークを引き起こす可能性があるからです。

引用元

例えば、ある友人がよくやるのですが、それのどこが悪いのか、みんなに見られてしまうのです

テストテーブルから偶数を削除する

コピーコード コードは以下の通りです。

local test = { 2, 3, 4, 8, 9, 100, 20, 13, 15, 7, 11}
for i, v in ipairs( test ) do
    if v % 2 == 0 then
        table.remove(test, i)
    end
end

for i, v in ipairs( test ) do
    print(i ... "====" . v)
end


印刷結果を表示します。
コピーコード コードは以下の通りです。

1====3
2====8
3====9
4====20
5====13
6====15
7====7
8====11
[Finished in 0.0s]

何かおかしいですよね?なんで20が残ってるんだ?トラバーサルで削除するとこうなるんだよ。

どうすればいいのですか?

さあ、はじめましょう

コピーコード コードは以下の通りです。

local test = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p' }
local remove = { a = true, b = true, c = true, e = true, f = true, p = true }

local function dump(table)
    for k, v in pairs( table ) do
        print(k)
        print(v)
        print("*********")
    end
end


注:一般的にループ内で削除することはありません。ループ内で削除すると、何らかのエラーが発生します。上の例のように、削除テーブルを作成して、削除されるものを真としてマークすることは可能です

方法1 後ろから前に削除する

コピーコード コードは以下の通りです。

for i = #test, 1, -1 do
    if remove[test[i]] then
        table.remove(test, i)
    end
end

dump(test)


手前から奥に行くのはいかがでしょうか。友達同士でテストしてみてください。table.remove操作の後、後ろの要素が前に移動し、この時、後続の削除インデックスに対応する要素は、前のインデックスに対応する要素ではなくなっています。


削除中の方法2

コピーコード コードは以下の通りです。

 local i = 1
while i <= #test do
    if remove[test[i]] then
        table.remove(test, i)
    else
        i = i + 1
    end
end

方法3 removeItemはクイックで提供

コピーコード コードは以下の通りです。

 function table.removeItem(list, item, removeAll)
    local rmCount = 0
    for i = 1, #list do
        if list[i - rmCount] == item then
            table.remove(list, i - rmCount)
            if removeAll then
                rmCount = rmCount + 1
            else
                break
            end
        end
    end
end

for k, v in pairs( remove ) do
    table.removeItem(test, k)
end

dump(test)