Bagaimana cara memeriksa apakah sebuah tabel berisi elemen di Lua?

98

Apakah ada metode untuk memeriksa apakah tabel berisi nilai? Saya memiliki fungsi (naif) saya sendiri, tetapi saya bertanya-tanya apakah ada sesuatu yang "resmi" untuk itu? Atau sesuatu yang lebih efisien ...

function table.contains(table, element)
  for _, value in pairs(table) do
    if value == element then
      return true
    end
  end
  return false
end

Ngomong-ngomong, alasan utama saya menggunakan fungsi ini adalah menggunakan tabel sebagai set, yaitu tanpa elemen duplikat. Apakah ada hal lain yang bisa saya gunakan?

Wookai
sumber
3
apa arti notasi _,?
Martin
24
Ini hanyalah variabel "sampah" bernama _. pairs()kembali key, value, tetapi dalam contoh ini saya hanya membutuhkan nilainya. Ini adalah semacam konvensi (diadopsi dalam buku "Pemrograman dalam Lua" lua.org/pil/index.html ) untuk menggunakan _variabel ini untuk menyimpan hal-hal yang tidak Anda perlukan.
Wookai
Saya telah melihat konvensi penamaan variabel "sampah" yang _digunakan dalam Python dan JavaScript, juga.
iono

Jawaban:

117

Anda dapat menempatkan nilai sebagai kunci tabel. Sebagai contoh:

function addToSet(set, key)
    set[key] = true
end

function removeFromSet(set, key)
    set[key] = nil
end

function setContains(set, key)
    return set[key] ~= nil
end

Ada contoh yang lebih lengkap sini .

interjay
sumber
13
Seorang pengguna anonim mengusulkan perbaikan berikut untuk kode Anda: Jika nilai dalam set dengan kunci tertentu adalah FALSE maka fungsi setContains () mengembalikan nilai salah meskipun ada item dalam tabel dengan kunci yang ditentukan. baris "return set [key] ~ = nil" memperbaiki kesalahan itu.
oers
Mungkin jugafunction keysOfSet(set) local ret={} for k,_ in pairs(set) do ret[#ret+1]=k end return ret end
Jesse Chisholm
24

Mengingat representasi Anda, fungsi Anda seefisien yang bisa dilakukan. Tentu saja, seperti yang dicatat oleh orang lain (dan seperti yang dipraktikkan dalam bahasa yang lebih tua dari Lua), solusi untuk masalah Anda yang sebenarnya adalah mengubah representasi. Saat Anda memiliki tabel dan menginginkan set, Anda mengubah tabel menjadi set dengan menggunakan elemen set sebagai kunci dan truesebagai nilainya. 1 untuk interjay.

Norman Ramsey
sumber
2

Saya tidak dapat memikirkan cara lain untuk membandingkan nilai, tetapi jika Anda menggunakan elemen set sebagai kuncinya, Anda dapat menyetel nilainya ke selain nol. Kemudian Anda mendapatkan pencarian cepat tanpa harus mencari di seluruh tabel.

Joel
sumber
2

Saya tahu ini adalah posting lama, tetapi saya ingin menambahkan sesuatu untuk anak cucu. Cara sederhana untuk menangani masalah yang Anda hadapi adalah dengan membuat tabel lain, dari nilai ke kunci.

yaitu. Anda memiliki 2 tabel yang memiliki nilai yang sama, satu menunjuk satu arah, satu menunjuk ke arah lain.

function addValue(key, value)
    if (value == nil) then
        removeKey(key)
        return
    end
    _primaryTable[key] = value
    _secodaryTable[value] = key
end

function removeKey(key)
    local value = _primaryTable[key]
    if (value == nil) then
        return
    end
    _primaryTable[key] = nil
    _secondaryTable[value] = nil
end

function getValue(key)
    return _primaryTable[key]
end

function containsValue(value)
    return _secondaryTable[value] ~= nil
end

Anda kemudian dapat meminta tabel baru untuk melihat apakah tabel tersebut memiliki 'elemen' kunci. Ini mencegah kebutuhan untuk mengulangi setiap nilai dari tabel lainnya.

Jika ternyata Anda tidak dapat benar-benar menggunakan 'elemen' sebagai kunci, karena itu bukan string misalnya, tambahkan checksum atau tostringdi atasnya misalnya, lalu gunakan itu sebagai kuncinya.

Mengapa Anda ingin melakukan ini? Jika tabel Anda sangat besar, jumlah waktu untuk mengulangi setiap elemen akan signifikan, sehingga Anda tidak dapat melakukannya terlalu sering. Overhead memori tambahan akan relatif kecil, karena akan menyimpan 2 penunjuk ke objek yang sama, bukan 2 salinan dari objek yang sama. Jika tabel Anda sangat kecil, maka itu tidak akan menjadi masalah, bahkan mungkin lebih cepat untuk mengulang daripada mencari peta lain.

Namun kata-kata dalam pertanyaan tersebut sangat menyarankan bahwa Anda memiliki banyak item untuk ditangani.

James
sumber
Penjelasan yang bagus, tetapi tidak benar-benar menambah apa pun pada diskusi. Mungkin akan menjadi ide yang lebih baik untuk mengedit jawaban interjay.
bcdan
1
Juga, '.key' harus diganti dengan '[key]' di mana pun dalam kode ini (sama dengan 'nilai')
Njol