Apa cara terbaik untuk menguji apakah daftar berisi nilai yang diberikan di Clojure?
Secara khusus, perilaku contains?
saat ini membingungkan saya:
(contains? '(100 101 102) 101) => false
Saya jelas bisa menulis fungsi sederhana untuk menelusuri daftar dan menguji kesetaraan, tetapi pasti ada cara standar untuk melakukan ini?
data-structures
clojure
mikera
sumber
sumber
Jawaban:
Ah,
contains?
... seharusnya salah satu dari lima FAQ teratas: Clojure.Itu tidak memeriksa apakah koleksi berisi nilai; itu memeriksa apakah suatu item dapat diambil dengan
get
atau, dengan kata lain, apakah koleksi berisi kunci. Ini masuk akal untuk set (yang dapat dianggap sebagai membuat tidak ada perbedaan antara kunci dan nilai-nilai), peta (jadi(contains? {:foo 1} :foo)
adalahtrue
) dan vektor (tapi catatan itu(contains? [:foo :bar] 0)
adalahtrue
, karena kunci di sini adalah indeks dan vektor yang bersangkutan tidak "mengandung" yang indeks0
!).Untuk menambah kebingungan, dalam kasus di mana tidak masuk akal untuk meneleponPembaruan: Di Clojure ≥ 1,5contains?
, itu hanya kembalifalse
; inilah yang terjadi di(contains? :foo 1)
dan juga(contains? '(100 101 102) 101)
.contains?
lemparan ketika menyerahkan objek jenis yang tidak mendukung tes "keanggotaan kunci" yang dimaksud.Cara yang benar untuk melakukan apa yang Anda coba lakukan adalah sebagai berikut:
Saat mencari salah satu dari banyak item, Anda dapat menggunakan set yang lebih besar; ketika mencari
false
/nil
, Anda dapat menggunakanfalse?
/nil?
- karena(#{x} x)
mengembalikanx
, dengan demikian(#{nil} nil)
adalahnil
; saat mencari salah satu dari beberapa item yang beberapa di antaranya mungkinfalse
ataunil
, Anda dapat menggunakan(Perhatikan bahwa barang dapat dikirimkan ke
zipmap
dalam jenis koleksi apa pun.)sumber
(some #{101} '(100 101 102))
mengatakan bahwa "sebagian besar waktu ini berhasil". Bukankah adil mengatakan bahwa itu selalu berhasil? Saya menggunakan Clojure 1.4 dan dokumentasi menggunakan contoh semacam ini. Ini bekerja untuk saya dan masuk akal. Apakah ada kasus khusus yang tidak berfungsi?false
ataunil
- lihat paragraf berikut. Pada catatan terpisah, di Clojure 1.5-RC1contains?
melempar pengecualian ketika diberi koleksi non-kunci sebagai argumen. Saya kira saya akan mengedit jawaban ini ketika rilis terakhir keluar.Inilah utilisasi standar saya untuk tujuan yang sama:
sumber
nil
danfalse
. Sekarang mengapa ini bukan bagian dari clojure / core?seq
mungkin bisa diubah namanya menjadicoll
, untuk menghindari kebingungan dengan fungsiseq
?seq
di dalam tubuh, tidak ada konflik dengan parameter dengan nama yang sama. Tapi jangan ragu untuk mengedit jawabannya jika Anda berpikir penggantian nama akan membuatnya lebih mudah untuk dipahami.(boolean (some #{elm} coll))
jika Anda tidak perlu khawatirnil
ataufalse
.Anda selalu dapat memanggil metode java dengan sintaks .methodName.
sumber
contains?
, Qc Na memukulnya dengan Bô dan berkata: "Murid bodoh! Anda harus menyadari tidak ada sendok. Itu semua hanya Java di bawahnya! Gunakan notasi titik.". Pada saat itu, Anton menjadi tercerahkan.Saya tahu bahwa saya sedikit terlambat, tetapi bagaimana dengan:
Akhirnya di clojure 1.4 output benar :)
sumber
(set '(101 102 103))
sama dengan%{101 102 103}
. Jadi jawaban Anda dapat ditulis sebagai(contains? #{101 102 103} 102)
.'(101 102 103)
ke set.Bekerja, tetapi di bawah ini lebih baik:
sumber
Untuk apa nilainya, ini adalah implementasi sederhana saya dari fungsi berisi daftar:
sumber
(defn list-contains? [pred coll value] (let [s (seq coll)] (if s (if (pred (first s) value) true (recur (rest s) value)) false)))
Jika Anda memiliki vektor atau daftar dan ingin memeriksa apakah suatu nilai terkandung di dalamnya, Anda akan menemukan bahwa
contains?
itu tidak berfungsi. Michał telah menjelaskan alasannya .Ada empat hal yang dapat Anda coba dalam hal ini:
Pertimbangkan apakah Anda benar-benar membutuhkan vektor atau daftar. Jika Anda menggunakan set sebagai gantinya ,
contains?
akan berfungsi.Gunakan
some
, balutkan target dalam satu set, sebagai berikut:Pintasan set-as-function tidak akan berfungsi jika Anda mencari nilai palsu (
false
ataunil
).Dalam kasus ini, Anda harus menggunakan fungsi predikat bawaan untuk nilai itu,
false?
ataunil?
:Jika Anda harus sering melakukan pencarian seperti ini, tuliskan fungsinya :
Juga, lihat jawaban Michał untuk cara memeriksa apakah ada dari beberapa target yang terkandung dalam suatu urutan.
sumber
Berikut adalah fungsi cepat dari utilitas standar saya yang saya gunakan untuk tujuan ini:
sumber
Inilah solusi Lisp klasik:
sumber
some
berpotensi paralel di seluruh core yang tersedia.Saya telah membangun versi jg-faustus dari "daftar-berisi?". Sekarang dibutuhkan sejumlah argumen.
sumber
Ini sesederhana menggunakan set - mirip dengan peta, Anda bisa menjatuhkannya di posisi fungsi. Ini mengevaluasi nilai jika di set (yang benar) atau
nil
(yang palsu):Jika Anda mengecek vektor / daftar berukuran cukup yang tidak akan Anda miliki sampai runtime, Anda juga dapat menggunakan
set
fungsi:sumber
Cara yang disarankan adalah menggunakan
some
dokumentasi set - see untukclojure.core/some
.Anda kemudian dapat menggunakan
some
dalam predikat benar / salah nyata, missumber
if
true
danfalse
?some
sudah mengembalikan nilai true-ish dan false-ish.sumber
contoh penggunaan (yang? [1 2 3] 3) atau (yang? # {1 2 3} 4 5 3)
sumber
Karena Clojure dibangun di Jawa, Anda dapat dengan mudah memanggilnya
.indexOf
fungsi Java. Fungsi ini mengembalikan indeks elemen apa pun dalam koleksi, dan jika tidak dapat menemukan elemen ini, mengembalikan -1.Memanfaatkan ini kita bisa mengatakan:
sumber
Masalah dengan solusi 'disarankan' adalah rusak ketika nilai yang Anda cari adalah 'nihil'. Saya lebih suka solusi ini:
sumber
Ada fungsi yang nyaman untuk tujuan ini di perpustakaan Tupelo . Secara khusus, fungsi
contains-elem?
,contains-key?
dancontains-val?
sangat berguna. Dokumentasi lengkap ada di dokumen API .contains-elem?
adalah yang paling umum dan ditujukan untuk vektor atau clojure lainnyaseq
:Di sini kita melihat bahwa untuk rentang bilangan bulat atau vektor campuran,
contains-elem?
berfungsi seperti yang diharapkan untuk elemen yang ada dan tidak ada dalam koleksi. Untuk peta, kami juga dapat mencari pasangan nilai kunci apa saja (dinyatakan sebagai vektor len-2):Juga mudah untuk mencari satu set:
Untuk peta & set, lebih mudah (& lebih efisien) untuk digunakan
contains-key?
untuk menemukan entri peta atau elemen set:Dan, untuk peta, Anda juga dapat mencari nilai dengan
contains-val?
:Seperti yang terlihat dalam tes, masing-masing fungsi ini bekerja dengan benar ketika mencari
nil
nilai.sumber
Pilihan lain:
Gunakan java.util.Collection # berisi ():
sumber