Luaテーブルが空である(エントリが含まれていない)かどうかを確認する最も効率的な方法は?


120

テーブルが空である(つまり、現在配列スタイルの値もdictスタイルの値も含まれていない)かどうかを判断する最も効率的な方法は何ですか?

現在、私は使用していnext()ます:

if not next(myTable) then
    -- Table is empty
end

より効率的な方法はありますか?

注:#演算子は、テーブル内の配列スタイルの値のみを操作するため、ここでは十分ではありません。両方とも0を返すため、#{test=2}区別できません。#{}また、テーブル変数がnil十分でないかどうかを確認しても、nil値ではなく、エントリが0のテーブル(つまり{})。

回答:


151

あなたのコードは効率的ですが間違っています。(検討してください{[false]=0}。)正しいコードは

if next(myTable) == nil then
   -- myTable is empty
end

最大の効率を得るにはnext、ローカル変数にバインドする必要があります。たとえば、

...
local next = next 
...
... if next(...) ...

1
技術的な正確さの良い点。元のコードを利用していた特定のケースではfalse、期待されるキーではないのでif not問題nilなく機能しますが、将来的には、良い習慣として、代わりに比較する習慣をつけるでしょう。そして、はい、速度を上げるために、一般的なユーティリティ関数をローカル変数にバインドしています。入力ありがとうございます。
アンバー

1
コードが意図したとおりに機能する場合、間違いに同意するのは難しいと思います
RD Alkire

4
なぜ私たちはスピードを上げるのlocal nextですか?
Moberg、

2
@Mobergこれは、LUAがその名前空間を処理する方法が原因です。非常に馬鹿げたバージョンは、最初にローカルテーブルを登るのでlocal next、現在のブロックにがある場合はそれを使用し、次に次のブロックに登って繰り返します。ローカルから外れると、グローバルネームスペースが使用されます。これは馬鹿げたバージョンですが、結局のところ、それは間違いなくプログラム速度の違いを意味します。
ATaco

@Mobergは、lua 5.2および5.3のコンテキストで、あまり機能が低下していないバージョンですが、非ローカルはupvalまたは_ENVルックアップです。upvalは間接的な追加のレイヤーを通過する必要がありますが、_ENVルックアップはテーブルルックアップです。地元ではVM内のレジスタであるのに対し
異議Rumed

1

1つの可能性は、メタテーブルの「newindex」キーを使用して、要素の数を数えることです。ないものを割り当てるnil場合は、カウンターをインクリメントします(カウンターはメタテーブルにも存在する可能性があります)。また、割り当てる場合nilは、カウンターをデクリメントします。

空のテーブルのテストは、カウンターを0でテストすることです。

これがメタテーブルのドキュメントへのポインタです

私はあなたのソリューションが好きですが、正直なところ、私のソリューションが全体的に高速であるとは思いません。


5
元の質問は、「配列」エントリだけを数えることではありません。
lhf 2009

3
0x6の提案は、配列スタイルのエントリに固有のものではありません(newindexは数値インデックスと非数値インデックスの両方で機能します)。ただし、nilキーがすでにテーブルに存在する場合、__ newindexはトリガーされないため、主な問題はいつが割り当てられるかを検出することです。
アンバー

3
仕事にこのトリックのために、メタテーブルは、両方を実装しなければならない__index__newindex影のテーブルに実際のデータを格納し、実際のテーブルにはそのように空に保ち、__indexすべてで呼び出されます。大声で考えると、1回の検索で発生するコストはそれだけの価値があるとは思えません。
RBerteig 2009

0

これはおそらくあなたが欲しかったものです:

function table.empty (self)
    for _, _ in pairs(self) do
        return false
    end
    return true
end

a = { }
print(table.empty(a))
a["hi"] = 2
print(table.empty(a))
a["hi"] = nil
print(table.empty(a))

出力:

true
false
true

11
next()ループするよりも効率的(かつ簡潔)ですpairs()
アンバー

8
実際、ループオーバーpairs() 基本的にこのnext()手法を使用するだけですが、オーバーヘッドが大きくなります。
dubiousjim

7
また、標準tableライブラリへの書き込みはお勧めしません。
Ti Strga 14

-1

オーバーロードされた場合に__eqの評価を回避することをお勧めします。

if rawequal(next(myTable), nil) then
   -- myTable is empty
end

または

if type(next(myTable)) == "nil" then
   -- myTable is empty
end

1
私はこの答えがなぜ反対票だったのかを理解しようとしているLua noobです。Luaでは、「2つのオブジェクトのメタメソッドが異なる場合、等価演算の結果はメタメソッドを呼び出さずにfalseになる」と私は推測しています。(引用は、このページの下部にあるlua.orgのLuaのプログラミングからです)。nilの__eqオーバーロードを回避する必要がなくなりますか?
SansWit

-1

蛇を試して、私のために働きます

serpent = require 'serpent'

function vtext(value)
  return serpent.block(value, {comment=false})
end

myTable = {}

if type(myTable) == 'table' and vtext(myTable) == '{}' then
   -- myTable is empty
end

-2

これはどう ?

if endmyTable[1] == nil then
  -- myTable is empty
end

1
これは、インデックスとして文字列として使用されるテーブルでは機能しません
SamHoque

-3

私はこれが古いことを知っており、どういうわけかあなたを誤解しているかもしれませんが、それは単にテーブルを空にしたいということです。私が間違えない限り、単にそれを再作成することでそれをクリアすることができます。これは、以下の構文で実行できます。

yourtablename = {} -- this seems to work for me when I need to clear a table.

4
それは問題ではありません。
Yu Hao

-6

を使用してみてください#。テーブルにあるすべてのインスタンスを返します。テーブルにインスタンスがない場合は、次を返します0

if #myTable==0 then
print('There is no instance in this table')
end

1
質問者は、それでは#ここでは十分ではなく、理由を説明します。これがこれらの理由を回避する理由を説明できますか?
2017年

まあ...わからない。私はこれが新しいので、私が知っている唯一の方法は#を使用することです
arthurgps2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.