Bir Lua tablosundaki giriş sayısı nasıl alınır?


132

Kulağa "senin için google'layayım" sorusuna benziyor, ancak bir şekilde yanıt bulamıyorum. Lua #operatörü yalnızca tamsayı anahtarlı girişleri sayar ve bu şekilde 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"

Tüm girişlerin sayısını saymadan nasıl alabilirim ?


3
@lhf: Gördüğü her nesneyi hatırlayan bir serileştirici yazdım ve bir dahaki sefere onu gördüğünde nesne yerine bir tamsayı gönderimi yayıyor. Bu yazmak için doğal bir yol gibi bir şey dictionary[value] = #dictionary + 1, #sayısını temsil tüm nesneler. Ne ben sana neden acaba olduğunu yok bunu istiyor: tüm aklı başında # (kaizer.se tarafından cevap bakınız) kullanım durumları, bütün nesnelerin sayısı tam olarak zaten neyi # getirilere eşit; Her şeyi # saymak kesinlikle bir gelişme gibi görünüyor. Tabii ki ben bir Lua acemisiyim ve asıl noktayı kaçırıyor olabilirim.
Roman Starkov

32
@lhf: Programcının yeterliliğini, neden tüm makul programlama dillerinin basit bir işlevi olan bir şeyi yapması gerektiğini sorarak sorgulamanız hoş değil.
Timwi

5
@Timwi: Lua dili yazarlarından birine Lua'nın "makul" programlama dilleri arasında olmadığını söylemen hiç hoş değil. ;-) BTW, bu bilgiye de hiç ihtiyacım olmadı.
Alexander Gladysh

5
Tek bir dilin her özelliğini hiç kullandığımı sanmıyorum . Bu, başkalarına yararlı olmadıkları anlamına gelmez :)
Roman Starkov

7
@sylvanaar Bence #operatör sadece kötü tanımlanmış. Bu çok kolay bir şekilde düzeltilebilir: birincisi, #deterministik yapın ve ikinci olarak, kesin sayımı elde etmek için yeni bir operatör veya işlev ekleyin. Hikayenin sonu ... Neden bu kadar inatçı olmak zorundalar? :)
Roman Starkov

Yanıtlar:


129

Sorudaki çözüme zaten sahipsiniz - tek yol tüm tabloyu ile yinelemektir pairs(..).

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

Ayrıca, "#" operatörünün tanımının bundan biraz daha karmaşık olduğuna dikkat edin. Bu tabloyu alarak bunu açıklayayım:

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

Kılavuza göre , 3, 5 ve 9'dan herhangi biri için geçerli sonuçlardır #t. Kullanmanın tek mantıklı yolu, sıfır değerleri olmayan bir bitişik bölümden oluşan dizilerdir.


42
Lua ile yaşadığım deneyimin hatırasında hala ürperiyorum, gibi temel bir operatörün dönüş değerinin #deterministik olmadığını ilk fark ettim .
Roman Starkov

5
Oh, muhtemelen belirleyicidir. C standardının uygulama tanımlı davranış olarak bir şey bırakması ile tamamen aynı şeydir. Bunun böyle olmasının nedeni, farklı uygulayıcıların farklı uygulama seçenekleri seçebilmesidir.
Nakedible

19
According to the manual, any of 3, 5 and 9 are valid results for #t. Kılavuza göre, sıralı olmayanlarda # çağırma tanımsızdır . Bu, herhangi bir sonucun (-1, 3, 3.14, 5, 9) geçerli olduğu anlamına gelir .
cubuspl42

6
Geçerli sonuçlarla ilgili olarak: u0b34a0f6ae Lua 5.1 için doğru iken cubuspl42, Lua 5.2 için doğrudur. Her iki durumda da, her şey tamamen çılgınca.
Jeremy

9
Sırasız bir # üzerinde bir istisna oluşturmaması gerçeği, lua kullanmayı biraz daha iyi hissetmek için kendinizi kesmek gibi yapan şeylerden sadece biridir.
boatcoder

21

Girişlerin sayısını izlemek için bir meta-tablo oluşturabilirsiniz, bu bilgi sıkça gerekliyse, bu yinelemeden daha hızlı olabilir.


Bu yöntemle girişleri silmenin uygun bir yolu var mı?
u0b34a0f6ae

Ne yazık ki, __newindex işlevi, dizin mevcut olmadığı sürece nil atamalarda çalışmıyor gibi görünüyor, bu nedenle, özel bir işlev aracılığıyla girişi kaldırmanız gerekecek gibi görünüyor.
ergosys

1
Verileri ayrı bir tabloda depolamalısınız (örneğin __index ve __newindex için yukarı değer olarak erişilebilir). Daha sonra her tablo erişimi için hem __index hem de __newindex etkinleşir. Yine de performansın kabul edilebilir olup olmadığını kontrol etmelisiniz.
Alexander Gladysh

@Alexander: Ah evet, ve sonra bir sonraki tökezleme noktası: Eğer tabloya vekalet verirseniz, o zaman çiftlere göre normal yineleme çalışmaz. Bunu Lua 5.2'de çözmenin mümkün olacağını duydum.
u0b34a0f6ae

5.2'de __pairs ve __ipairs metamethods olacaktır ... 5.1'de yapmak istiyorsanız, pair () işlevini kendi işlevinizle değiştirmeniz gerekir. Ama bu muhtemelen çok fazla. :-)
Alexander Gladysh

3

Bir yolu var, ancak hayal kırıklığı yaratabilir: sayımı saklamak için ek bir değişken (veya tablonun alanından birini) kullanın ve her ekleme yaptığınızda bunu artırın.

count = 0
tbl = {}

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

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

Başka yolu yoktur, # operatörü yalnızca ardışık anahtarlara sahip dizi benzeri tablolarda çalışır.


3
Tarafından belirtildiği gibi bu durum bir proxy masa ve metamethods ile otomatik hale getirilebilir ergosys cevabı
RBerteig

Yorumlardan proxyable / metamethods olayının henüz bu senaryoyu tam olarak desteklemediği izlenimini edindim, bu yüzden bunu şu anda mevcut olan en iyi yol olarak kabul edeceğim.
Roman Starkov

Sayma, tablolar için tek yoldur ve tabloları oluştururken satır eklemek, sayıma her ihtiyacınız olduğunda bunları saymak için bir işlevden daha iyidir. Sayıma ayarlanan değer ile sonuna bir anahtar ekleyebilirsiniz.
Henrik Erlandsson

2

Bir tablodaki girdi sayısını almanın bildiğim en kolay yolu '#' kullanmaktır. #tableName, numaralandırıldıkları sürece girişlerin sayısını alır:

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

Ne yazık ki, numaralandırılmamışlarsa işe yaramayacak.


2

Penlight kitaplığını kullanabilirsiniz . Bu, sizetablonun gerçek boyutunu veren bir işleve sahiptir.

Lua'da programlama yaparken ve eksikken ihtiyaç duyabileceğimiz birçok işlevi gerçekleştirdi.

İşte kullanmak için örnek.

> 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
Bir yanıt gönderirken, bir soruyu doğrudan yanıtlayan minimum miktarda kod göndermeniz ve kodun soruyu nasıl yanıtladığını açıklamanız önerilir. Buraya bakın .
cst1992

__newindexyalnızca yeni bir anahtar tanımlandığında çağırır, bu nedenle var olan bir anahtarı __newindexayarladığımızda arama şansı yoktur nil.
Frank AK

-1

tablonun elemanları insert yöntemi ile eklendiğinde, getn doğru bir şekilde dönecektir. Aksi takdirde, tüm unsurları saymamız gerekir

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

2'yi doğru yazdıracak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.