Cara paling efisien untuk menentukan apakah tabel Lua kosong (tidak berisi entri)?

120

Apa cara paling efisien untuk menentukan apakah sebuah tabel kosong (yaitu, saat ini tidak berisi nilai gaya array maupun nilai gaya dikt)?

Saat ini, saya menggunakan next():

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

Apakah ada cara yang lebih efisien?

Catatan: #Operator tidak mencukupi di sini, karena hanya beroperasi pada nilai gaya array dalam tabel - sehingga #{test=2}tidak dapat dibedakan dari #{}karena keduanya menghasilkan 0. Perhatikan juga bahwa memeriksa apakah variabel tabel niltidak mencukupi karena saya tidak mencari nil, tetapi tabel dengan 0 entri (yaitu {}).

Amber
sumber

Jawaban:

151

Kode Anda efisien tetapi salah. (Pertimbangkan {[false]=0}.) Kode yang benar adalah

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

Untuk efisiensi maksimum, Anda ingin mengikat nextke variabel lokal, misalnya,

...
local next = next 
...
... if next(...) ...
Norman Ramsey
sumber
1
Poin bagus tentang kebenaran teknis; dalam kasus tertentu saya telah menggunakan kode asli, falsetidak akan menjadi kunci yang diharapkan sehingga if notberfungsi dengan baik, tetapi saya mungkin akan membuat kebiasaan untuk membandingkannya nildi masa depan, sama seperti kebiasaan yang baik. Dan ya, saya telah mengikat fungsi utilitas umum ke vars lokal untuk kecepatan. Terima kasih atas masukannya.
Amber
1
Saya merasa sulit untuk menyetujui kesalahan saat kode berfungsi sebagaimana mestinya
RD Alkire
4
Mengapa kita menambah kecepatan dengan melakukan local next?
Moberg
2
@Moberg Ini karena cara LUA menangani namespace-nya. Versi yang sangat bodoh, adalah pertama-tama akan memanjat tabel lokal, jadi jika ada local nextdi blok saat ini, ia akan menggunakannya, lalu naik ke blok berikutnya, dan ulangi. Setelah keluar dari penduduk setempat, itu hanya akan menggunakan Global Namespace. Ini adalah versi bodohnya, tetapi pada akhirnya, itu berarti perbedaan dalam hal kecepatan program.
ATaco
@Moberg versi yang tidak terlalu bodoh, dalam konteks lua 5.2 & 5.3, adalah bahwa non-lokal adalah pencarian upvals atau _ENV. Upval harus melalui lapisan tambahan tipuan, sedangkan pencarian _ENV adalah pencarian tabel. Sedangkan lokal adalah register di VM
Demur Rumed
1

Salah satu kemungkinannya adalah menghitung jumlah elemen, dengan menggunakan kunci "indeks baru" yang dapat diukur. Saat menugaskan sesuatu yang tidak nil, tambah penghitung (penghitung juga bisa hidup di metatabel) dan saat menetapkan nil, kurangi penghitung.

Pengujian untuk tabel kosong akan menguji penghitung dengan 0.

Berikut adalah penunjuk ke dokumentasi yang dapat diukur

Saya menyukai solusi Anda, dan sejujurnya saya tidak dapat berasumsi bahwa solusi saya lebih cepat secara keseluruhan.

0x6adb015
sumber
5
Pertanyaan awal bukanlah tentang menghitung entri "larik" saja.
lhf
3
Saran 0x6 tidak khusus untuk entri gaya larik (indeks baru berfungsi untuk indeks numerik dan non-numerik). Namun, masalah utama adalah mendeteksi saat nilditetapkan, karena __newindex tidak memicu jika kunci sudah ada di tabel.
Amber
3
Agar trik ini berhasil, metatabel harus mengimplementasikan keduanya __indexdan __newindex, menyimpan data aktual dalam tabel bayangan dan mengosongkan tabel nyata sehingga __indexakan dipanggil sama sekali. Berpikir keras, saya curiga bahwa biaya yang meningkat dari setiap pencarian tidak sepadan.
RBerteig
0

Ini mungkin yang Anda inginkan:

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))

Keluaran:

true
false
true
FichteFoll
sumber
11
next()lebih efisien (dan lebih ringkas) daripada mengulang pairs().
Amber
8
Bahkan, perulangan atas pairs() adalah dasarnya hanya menggunakan next()teknik, tetapi dengan lebih banyak overhead.
dubiousjim
7
Selain itu, tabletidak disarankan untuk menulis ke pustaka standar .
Ti Strga
-1

lebih baik hindari evaluasi __eq jika kelebihan beban.

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

atau

if type(next(myTable)) == "nil" then
   -- myTable is empty
end
Laurent Deniau
sumber
1
Saya seorang Lua noob yang mencoba memahami mengapa jawaban ini ditolak. Saya menduga itu karena di Lua, "jika dua objek memiliki metamethod yang berbeda, operasi persamaan menghasilkan false, bahkan tanpa memanggil metamethod apapun". (Kutipan ada di bagian bawah halaman ini dari Pemrograman di Lua di lua.org ). Apakah itu menghilangkan kebutuhan untuk menghindari __eq overloading nihil?
SansWit
-1

coba ular, bekerjalah untukku

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
Webrom
sumber
-2

Bagaimana dengan ini ?

if endmyTable[1] == nil then
  -- myTable is empty
end
Venkat Reddy
sumber
1
Ini tidak akan berfungsi pada tabel yang sebagai string sebagai indeks
SamHoque
-3

Saya tahu ini sudah tua, dan saya bisa saja salah paham, tetapi Anda hanya ingin meja kosong, kecuali Anda hanya memeriksa apakah itu benar dan Anda tidak benar-benar ingin atau membutuhkannya kosong, Anda dapat menghapusnya hanya dengan membuatnya kembali, kecuali saya salah. ini dapat dilakukan dengan sintaks di bawah ini.

yourtablename = {} -- this seems to work for me when I need to clear a table.
Michael reece
sumber
4
Bukan itu pertanyaannya.
Yu Hao
-6

Coba gunakan #. Ini mengembalikan semua contoh yang ada dalam tabel. Jika tidak ada contoh dalam tabel, maka itu kembali0

if #myTable==0 then
print('There is no instance in this table')
end
arthurgps2
sumber
1
Penanya mengatakan itu #tidak cukup di sini, dan memberikan alasan mengapa; dapatkah Anda menjelaskan mengapa hal ini menyinggung alasan tersebut?
ameed
baik ... saya tidak tahu. Saya baru dalam hal ini jadi satu-satunya cara yang saya tahu adalah menggunakan #
arthurgps2