Bagaimana cara mendapatkan jumlah entri dalam tabel Lua?


132

Kedengarannya seperti pertanyaan "biarkan saya google untuk Anda", tetapi entah bagaimana saya tidak dapat menemukan jawaban. #Operator Lua hanya menghitung entri dengan kunci integer, dan begitu juga 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"

Bagaimana cara saya mendapatkan jumlah semua entri tanpa menghitungnya?


3
@ lhf: Saya telah menulis serializer yang mengingat setiap objek yang telah dilihatnya, dan lain kali melihatnya serialis memancarkan referensi integer bukan objek. Cara alami untuk menulis ini adalah sesuatu seperti dictionary[value] = #dictionary + 1, di mana #merepresentasikan jumlah semua objek. Yang saya heran adalah mengapa Anda tidak menginginkan ini: dalam semua kasus penggunaan # untuk waras (lihat jawaban oleh kaizer.se), jumlah semua objek persis sama dengan apa yang sudah # dikembalikan; sepertinya membuat # hitung semuanya benar-benar perbaikan. Tentu saja saya seorang pemula Lua dan mungkin kehilangan intinya.
Roman Starkov

32
@ lhf: Tidak baik bagi Anda untuk mempertanyakan kompetensi programmer dengan menanyakan mengapa ia perlu melakukan sesuatu yang semua bahasa pemrograman yang masuk akal memiliki fungsi sederhana.
Timwi

5
@Timwi: Tidak baik jika Anda memberi tahu salah satu penulis bahasa Lua bahwa Lua tidak termasuk dalam bahasa pemrograman yang "masuk akal". ;-) BTW, saya tidak pernah membutuhkan informasi itu juga.
Alexander Gladysh

5
Saya rasa saya tidak pernah menggunakan setiap fitur dari satu bahasa. Itu tidak berarti mereka tidak berguna bagi orang lain :)
Roman Starkov

7
@ Sylvanaar Menurut pendapat saya, #operator hanya tidak jelas. Ini sangat mudah diperbaiki: pertama, buat #deterministik, dan kedua, kenalkan operator atau fungsi baru untuk mendapatkan jumlah yang sangat berarti. Akhir cerita ... Mengapa mereka harus begitu keras kepala? :)
Roman Starkov

Jawaban:


129

Anda sudah memiliki solusi dalam pertanyaan - satu-satunya cara adalah dengan mengulangi seluruh tabel pairs(..).

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

Juga, perhatikan bahwa definisi operator "#" sedikit lebih rumit dari itu. Izinkan saya menggambarkannya dengan mengambil tabel ini:

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

Menurut manual, salah satu dari 3, 5 dan 9 adalah hasil yang valid untuk #t. Satu-satunya cara yang waras untuk menggunakannya adalah dengan array dari satu bagian yang berdekatan tanpa nilai nil.


42
Saya masih bergidik mengingat pengalaman saya dengan Lua, ketika saya pertama kali menyadari bahwa nilai kembalinya operator dasar seperti #tidak deterministik.
Roman Starkov

5
Oh, itu sepertinya deterministik. Ini persis sama dengan ketika standar C meninggalkan sesuatu untuk menjadi implementasi yang didefinisikan perilaku. Alasannya seperti ini adalah bahwa implementator yang berbeda dapat memilih pilihan implementasi yang berbeda.
Nakedible

19
According to the manual, any of 3, 5 and 9 are valid results for #t. Menurut manual, memanggil # pada non-urutan tidak ditentukan . Itu berarti bahwa hasil apa pun (-1, 3, 3.14, 5, 9) valid.
cubuspl42

6
Mengenai hasil yang valid: u0b34a0f6ae benar untuk Lua 5.1, sedangkan cubuspl42 benar untuk Lua 5.2. Dalam kedua kasus itu, semuanya benar-benar gila.
Jeremy

9
Fakta bahwa # pada non-sequence tidak menghasilkan pengecualian hanyalah salah satu hal yang membuat penggunaan lua sedikit seperti memotong diri sendiri agar merasa lebih baik.
boatcoder

21

Anda dapat mengatur tabel meta untuk melacak jumlah entri, ini mungkin lebih cepat daripada iterasi jika informasi ini sering dibutuhkan.


Apakah ada cara mudah untuk menangani menghapus entri dengan metode ini?
u0b34a0f6ae

Sayangnya, tampaknya fungsi __newindex tidak diaktifkan pada tugas nihil kecuali indeks tidak ada, jadi sepertinya Anda harus menyalurkan penghapusan entri melalui fungsi khusus.
ergosys

1
Anda harus menyimpan data dalam tabel terpisah (misalnya diakses sebagai nilai tambah untuk __index dan __newindex). Kemudian __index dan __newindex akan diaktifkan untuk setiap akses tabel. Anda harus memeriksa apakah kinerjanya dapat diterima.
Alexander Gladysh

@Alexander: Ah ya, dan kemudian titik sandungan berikutnya: jika Anda proksi tabel, maka iterasi normal oleh pasangan tidak bekerja. Ini akan mungkin diselesaikan di Lua 5.2, saya dengar.
u0b34a0f6ae

Akan ada __pairs dan __pairs metamethods di 5.2 ... Jika Anda ingin melakukannya di 5.1, Anda harus mengganti fungsi pasangan () dengan milik Anda. Tapi itu mungkin terlalu banyak. :-)
Alexander Gladysh

3

Ada satu cara, tetapi mungkin mengecewakan: gunakan variabel tambahan (atau salah satu bidang tabel) untuk menyimpan hitungan, dan tambah setiap kali Anda membuat penyisipan.

count = 0
tbl = {}

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

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

Tidak ada cara lain, operator # hanya akan bekerja pada tabel seperti array dengan tombol berurutan.


3
Ini dapat diotomatisasi dengan tabel proxy dan metametode, seperti yang disebutkan oleh jawaban ergosys
RBerteig

Saya mendapat kesan dari komentar bahwa hal proxytable / metamethods belum sepenuhnya mendukung skenario ini, jadi saya akan menerima ini sebagai cara terbaik yang saat ini tersedia.
Roman Starkov

Menghitung adalah satu-satunya cara untuk tabel, dan menambahkan garis saat membuat tabel lebih baik daripada fungsi untuk menghitungnya setiap kali Anda membutuhkan hitungan. Anda dapat menambahkan kunci di bagian akhir dengan nilai yang ditetapkan ke penghitungan.
Henrik Erlandsson

2

Cara termudah yang saya tahu untuk mendapatkan jumlah entri dalam tabel adalah dengan '#'. #tableName mendapatkan jumlah entri selama mereka diberi nomor:

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

Sayangnya, jika mereka tidak diberi nomor, itu tidak akan berhasil.


2

Anda dapat menggunakan perpustakaan penalight . Ini memiliki fungsi sizeyang memberikan ukuran sebenarnya dari tabel.

Ini telah mengimplementasikan banyak fungsi yang mungkin kita perlukan saat pemrograman dan hilang di Lua.

Ini adalah contoh untuk menggunakannya.

> 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
Saat memposting jawaban, disarankan untuk mengirim kode minimal yang langsung menjawab pertanyaan, dan jelaskan bagaimana kode menjawab pertanyaan. Lihat di sini .
cst1992

__newindexhanya menelepon saat kunci baru __newindexditentukan , jadi tidak ada kesempatan untuk menelepon saat kami menyetel nilke kunci yang ada.
Frank AK

-1

tampaknya ketika elemen tabel ditambahkan dengan metode insert, getn akan kembali dengan benar. Kalau tidak, kita harus menghitung semua elemen

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

Ini akan mencetak 2 dengan benar

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.