Luaテーブルのエントリ数を取得するにはどうすればよいですか?


131

「グーグルで教えて」という質問のようですが、どういうわけか答えが見つかりません。Lua #演算子は整数キーを持つエントリのみをカウントし、そうしtable.getnます:

tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl))   -- prints "1     1"

count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count)            -- prints "2"

カウントせずにすべてのエントリの数を取得するにはどうすればよいですか?


3
@lhf:見たすべてのオブジェクトを記憶するシリアライザを作成しました。次にそれを見ると、オブジェクトの代わりに整数参照を発行します。これを書く自然な方法はのようなものでdictionary[value] = #dictionary + 1#すべてのオブジェクトの数を表します。どのような私が疑問に思うことは、あなたが理由ではありませんすべてに:これが欲しい正気の#のためのユースケース(kaizer.seで答えを参照)、すべてのオブジェクトの数はすでに何#リターンと正確に一致しています。#すべてをカウントすることは厳密に改善のようです。もちろん、私はLuaの初心者なので、要点を逃している可能性があります。
ローマン・スターコフ2010

32
@lhf:合理的なすべてのプログラミング言語が単純な機能を備えている理由をなぜプログラマーが行う必要があるのか​​を問うことによって、プログラマーの能力に疑問を呈するのはあなたにとって不快です。
Timwi、2010

5
@Timwi:Lua言語の作者の1人にLuaが「合理的な」プログラミング言語に属していないことを伝えるのは、あなたにとってうれしいことではありません。;-)ところで、私はその情報も必要としませんでした。
Alexander Gladysh 2010

5
私は、私は考えていない、これまで使用され、すべての単一言語の特徴を。それは彼らが他の人に役に立たないということではありません:)
Roman Starkov

7
@sylvanaar私の考えでは、#演算子は不明確です。これは非常に簡単に修正できます。1つ目は#決定論的で、もう1つは新しい演算子または関数を導入してダーンカウントを取得します。物語の終わり...なぜ彼らはそんなに頑固でなければならないのですか?:)
Roman Starkov

回答:


129

あなたはすでに問題の解決策を持っています-唯一の方法は、テーブル全体をで反復することpairs(..)です。

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

また、「#」演算子の定義はそれよりも少し複雑であることに注意してください。この表を見て、そのことを説明しましょう。

t = {1,2,3}
t[5] = 1
t[9] = 1

マニュアルによると、3、5、9のいずれもの有効な結果です#t。それを使用する唯一の健全な方法は、nil値のない1つの隣接する部分の配列を使用することです。


42
基本的な演算子のような戻り値は#確定的ではないことに最初に気付いたとき、私はLuaでの私の経験の記憶にまだ震えています。
ロマンスターコフ

5
ああ、それはおそらく確定的です。これは、C標準が何かを実装定義の動作のままにする場合とまったく同じです。このような理由は、異なる実装者が異なる実装の選択肢を選択できるためです。
Nakedible 2013

19
According to the manual, any of 3, 5 and 9 are valid results for #t。マニュアルによると、非シーケンスで#を呼び出すことは未定義です。つまり結果(-1、3、3.14、5、9)は有効です。
cubuspl42 2014年

6
有効な結果について:Lua 5.1ではu0b34a0f6aeが正しく、Lua 5.2ではcubuspl42が正しいです。どちらの場合でも、すべてが完全に異常です。
ジェレミー

9
#シーケンス以外で#が例外を生成しないという事実は、luaを使用することで、気分を良くするために自分自身をカットするようなものの1つにすぎません。
ボートコーダー2015年

20

エントリの数を追跡するようにメタテーブルを設定できます。この情報が頻繁に必要になる場合、これは反復よりも高速な場合があります。


この方法でエントリの消去を処理する便利な方法はありますか?
u0b34a0f6ae 2010

悲しいことに、インデックスが存在しない場合を除き、__ newindex関数はnil割り当てで起動しないようです。そのため、特別な関数を使用してエントリの削除を集中させる必要があるようです。
ergosys 2010

1
別のテーブルにデータを保存する必要があります(たとえば、__ indexおよび__newindexのアップバリューとしてアクセス可能)。次に、__ indexと__newindexの両方が、テーブルアクセスごとに起動します。ただし、パフォーマンスが許容範囲内かどうかを確認する必要があります。
アレクサンダーグラディッシュ2010

@アレクサンダー:ああそうです。次に次の問題点があります。テーブルをプロキシする場合、ペアによる通常の反復は機能しません。これはLua 5.2で解決できると聞きました。
u0b34a0f6ae 2010

5.2には__pairsと__ipairsメタメソッドがあります... 5.1で実行したい場合は、pairs()関数を独自のメタメソッドに置き換える必要があります。しかし、それは多すぎるでしょう。:-)
Alexander Gladysh 2010

3

方法は1つですが、期待はずれかもしれません。追加の変数(またはテーブルのフィールドの1つ)を使用してカウントを保存し、挿入するたびに値を増やします。

count = 0
tbl = {}

tbl["test"] = 47
count = count + 1

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

他に方法はありません。#演算子は、連続するキーを持つ配列のようなテーブルでのみ機能します。


3
これは、ergosysの回答
RBerteig

proxytable / metamethodsはまだこのシナリオを完全にはサポートしていないというコメントからの感想を受け取ったので、これを現在利用可能な最良の方法として受け入れます。
ロマン・スターコフ2010

カウントはテーブルの唯一の方法であり、テーブルの作成時に行を追加することは、カウントが必要になるたびにカウントする関数よりも優れています。カウントに値を設定して、最後にキーを追加できます。
Henrik Erlandsson 2014

2

テーブルのエントリ数を取得するために知っている最も簡単な方法は、「#」を使用することです。#tableNameは、番号が付けられている限り、エントリの数を取得します。

tbl={
    [1]
    [2]
    [3]
    [4]
    [5]
}
print(#tbl)--prints the highest number in the table: 5

悲しいことに、番号が付けられていないと機能しません。


2

あなたはペンライトライブラリを使用することができます。これにはsize、テーブルの実際のサイズを示す関数があります。

Luaでのプログラミングおよび欠落時に必要になる可能性のある機能の多くが実装されています。

こちらが使用例です。

> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3 
> a['blah'] = 24

> #a
0

> tablex.size(a)
3

1
local function CountedTable(x)
    assert(type(x) == 'table', 'bad parameter #1: must be table')

    local new_t = {}
    local mt = {}

    -- `all` will represent the number of both
    local all = 0
    for k, v in pairs(x) do
        all = all + 1
    end

    mt.__newindex = function(t, k, v)
        if v == nil then
            if rawget(x, k) ~= nil then
                all = all - 1
            end
        else
            if rawget(x, k) == nil then
                all = all + 1
            end
        end

        rawset(x, k, v)
    end

    mt.__index = function(t, k)
        if k == 'totalCount' then return all
        else return rawget(x, k) end
    end

    return setmetatable(new_t, mt)
end

local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }

assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)

1
回答を投稿するときは、質問に直接回答する最小限のコードを投稿し、コードが質問にどのように回答するかを説明することをお勧めします。こちらをご覧ください
cst1992

__newindex新しいキーが定義されたときにのみ呼び出すので、既存のキー__newindexに設定nilしたときに呼び出す機会はありません。
フランクAK

-1

テーブルの要素がinsertメソッドによって追加された場合、getnは正しく返されます。そうでなければ、すべての要素を数える必要があります

mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))

2を正しく印刷します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.