Saya ingin memfilter a java.util.Collection
berdasarkan predikat.
java
collections
filter
Kevin Wong
sumber
sumber
persons.removeIf(p -> p.getAge() <= 16);
Dengan asumsi bahwa Anda menggunakan Java 1.5 , dan bahwa Anda tidak dapat menambahkan Google Collections , saya akan melakukan sesuatu yang sangat mirip dengan yang dilakukan orang-orang Google. Ini sedikit variasi pada komentar Jon.
Pertama tambahkan antarmuka ini ke basis kode Anda.
Para pelaksana dapat menjawab ketika predikat tertentu benar untuk jenis tertentu. Misalnya Jika
T
ituUser
danAuthorizedUserPredicate<User>
mengimplementasikanIPredicate<T>
, kemudianAuthorizedUserPredicate#apply
kembali apakah disahkan padaUser
berwenang.Kemudian di beberapa kelas utilitas, bisa dibilang
Jadi, dengan asumsi bahwa Anda memiliki penggunaan di atas mungkin
Jika kinerja pada pemeriksaan linier menjadi perhatian, maka saya mungkin ingin memiliki objek domain yang memiliki koleksi target. Objek domain yang memiliki kumpulan target akan memiliki logika penyaringan untuk metode yang menginisialisasi, menambah dan mengatur koleksi target.
MEMPERBARUI:
Di kelas utilitas (katakanlah Predikat), saya telah menambahkan metode pilih dengan opsi untuk nilai default ketika predikat tidak mengembalikan nilai yang diharapkan, dan juga properti statis untuk params untuk digunakan di dalam IPredicate baru.
Contoh berikut mencari benda yang hilang di antara koleksi:
Contoh berikut, mencari sebuah instance dalam koleksi, dan mengembalikan elemen pertama dari koleksi sebagai nilai default ketika instance tidak ditemukan:
UPDATE (setelah rilis Java 8):
Sudah beberapa tahun sejak saya (Alan) pertama kali memposting jawaban ini, dan saya masih tidak percaya saya mengumpulkan poin SO untuk jawaban ini. Bagaimanapun, sekarang Java 8 telah memperkenalkan bahasa, jawaban saya sekarang akan sangat berbeda, dan lebih sederhana. Dengan Java 8, tidak perlu kelas utilitas statis yang berbeda. Jadi jika Anda ingin menemukan elemen 1 yang cocok dengan predikat Anda.
JDK 8 API untuk optionals memiliki kemampuan untuk
get()
,isPresent()
,orElse(defaultUser)
,orElseGet(userSupplier)
danorElseThrow(exceptionSupplier)
, serta fungsi lainnya 'monadik' sepertimap
,flatMap
danfilter
.Jika Anda hanya ingin mengumpulkan semua pengguna yang cocok dengan predikat, maka gunakan
Collectors
untuk mengakhiri streaming dalam koleksi yang diinginkan.Lihat di sini untuk contoh lebih lanjut tentang cara kerja stream Java 8.
sumber
val authorized = for (user <- users if user.isAuthorized) yield user
Gunakan CollectionUtils.filter (Koleksi, Predikat) , dari Apache Commons.
sumber
Cara "Terbaik" adalah permintaan yang terlalu luas. Apakah itu "terpendek"? "Tercepat"? "Dapat dibaca"? Saring di tempat atau ke koleksi lain?
Cara paling sederhana (tetapi tidak paling mudah dibaca) adalah dengan mengulanginya dan menggunakan metode Iterator.remove ():
Sekarang, agar lebih mudah dibaca, Anda dapat membungkusnya menjadi metode utilitas. Kemudian ciptakan antarmuka IPredicate, buat implementasi anonim dari antarmuka itu dan lakukan sesuatu seperti:
di mana filterInPlace () iterate collection dan panggil Predicate.keepIt () untuk mengetahui apakah instance disimpan dalam koleksi.
Saya tidak benar-benar melihat pembenaran untuk membawa perpustakaan pihak ketiga hanya untuk tugas ini.
sumber
stream()
fitur, tetapi tidak semua orang bisa bermain dengan mainan terbaru: PPertimbangkan Google Collections untuk kerangka kerja Koleksi yang diperbarui yang mendukung obat generik.
UPDATE : Pustaka koleksi google sekarang sudah tidak digunakan lagi. Anda harus menggunakan rilis terbaru dari Jambu Biji sebagai gantinya. Itu masih memiliki semua ekstensi yang sama ke kerangka koleksi termasuk mekanisme untuk penyaringan berdasarkan predikat.
sumber
Tunggu Java 8:
sumber
personList.removeIf(p -> p.age < 30);
Kurang bertele-tele. Juga, saya pernah mendengar pembicaraan tentang mulai menerapkan apis yang menerima dan mengembalikanStream
s daripadaCollection
s karenaStream
s sangat berguna dan cepat tetapi pergi ke / dari mereka adalah lambat.Sejak rilis awal Java 8, Anda dapat mencoba sesuatu seperti:
Misalnya, jika Anda memiliki daftar bilangan bulat dan Anda ingin memfilter angka yang> 10 lalu mencetak angka-angka itu ke konsol, Anda bisa melakukan sesuatu seperti:
sumber
Saya akan melempar RxJava di atas ring, yang juga tersedia di Android . RxJava mungkin tidak selalu menjadi pilihan terbaik, tetapi itu akan memberi Anda lebih banyak fleksibilitas jika Anda ingin menambahkan lebih banyak transformasi pada koleksi Anda atau menangani kesalahan saat memfilter.
Keluaran:
Rincian lebih lanjut tentang RxJava
filter
dapat ditemukan di sini .sumber
Pengaturan:
Penggunaan:
sumber
Bagaimana dengan Jawa biasa dan lurus?
Sederhana, mudah dibaca dan mudah (dan berfungsi di Android!) Tetapi jika Anda menggunakan Java 8, Anda dapat melakukannya dalam satu baris yang manis:
Perhatikan bahwa toList () diimpor secara statis
sumber
Apakah Anda yakin ingin memfilter Koleksi itu sendiri, bukan iterator?
lihat org.apache.commons.collections.iterators.FilterIterator
atau menggunakan versi 4 dari apache commons org.apache.commons.collections4.iterators.FilterIterator
sumber
Mari kita lihat cara memfilter Daftar JDK bawaan dan MutableList menggunakan Eclipse Collections .
Jika Anda ingin memfilter angka kurang dari 3, Anda akan mengharapkan output berikut.
Inilah cara Anda dapat memfilter menggunakan Java 8 lambda sebagai file
Predicate
.Inilah cara Anda bisa memfilter menggunakan kelas dalam anonim sebagai
Predicate
.Berikut adalah beberapa alternatif untuk memfilter daftar JDK dan Eclipse Collections MutableLists menggunakan pabrik Predicates .
Berikut adalah versi yang tidak mengalokasikan objek untuk predikat, dengan menggunakan pabrik Predicates2 sebagai gantinya dengan
selectWith
metode yang mengambil aPredicate2
.Terkadang Anda ingin memfilter pada kondisi negatif. Ada metode khusus dalam Eclipse Collections untuk itu
reject
.Metode
partition
akan mengembalikan dua koleksi, berisi elemen yang dipilih oleh dan ditolak olehPredicate
.Catatan: Saya pengendara untuk Eclipse Collections.
sumber
removeIf
pada daftar atau menetapkan untuk primitif?Dengan ForEach DSL Anda dapat menulis
Diberikan koleksi [The, quick, brown, fox, jumps, over, the, lazy, dog] ini menghasilkan [quick, brown, jumps, over, lazy], yaitu semua string lebih panjang dari tiga karakter.
Semua gaya iterasi yang didukung oleh ForEach DSL adalah
AllSatisfy
AnySatisfy
Collect
Counnt
CutPieces
Detect
GroupedBy
IndexOf
InjectInto
Reject
Select
Untuk detail lebih lanjut, silakan merujuk ke https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach
sumber
Metode Collections2.filter (Collection, Predicate) di perpustakaan Guava Google melakukan apa yang Anda cari.
sumber
Karena java 9
Collectors.filtering
diaktifkan:Jadi penyaringan harus:
Contoh:
sumber
Ini, dikombinasikan dengan kurangnya penutupan nyata, adalah keluhan terbesar saya untuk Jawa. Jujur, sebagian besar metode yang disebutkan di atas cukup mudah dibaca dan BENAR-BENAR efisien; namun, setelah menghabiskan waktu dengan .Net, Erlang, dll. Pemahaman daftar yang terintegrasi pada tingkat bahasa membuat semuanya jauh lebih bersih. Tanpa penambahan di tingkat bahasa, Java tidak akan sebersih banyak bahasa lain di area ini.
Jika kinerja adalah masalah besar, koleksi Google adalah cara untuk pergi (atau menulis utilitas predikat sederhana Anda sendiri). Sintaks Lambdaj lebih mudah dibaca oleh sebagian orang, tetapi tidak cukup efisien.
Dan kemudian ada perpustakaan yang saya tulis. Saya akan mengabaikan pertanyaan sehubungan dengan efisiensinya (ya, itu seburuk itu) ...... Ya, saya tahu itu jelas berdasarkan refleksi, dan tidak, saya tidak benar-benar menggunakannya, tetapi ia bekerja:
ATAU
sumber
JFilter http://code.google.com/p/jfilter/ paling cocok untuk kebutuhan Anda.
JFilter adalah pustaka sumber terbuka yang sederhana dan berkinerja tinggi untuk meminta koleksi kacang Jawa.
Fitur utama
sumber
Saya menulis kelas Iterable diperpanjang yang mendukung penerapan algoritma fungsional tanpa menyalin konten koleksi.
Pemakaian:
Kode di atas sebenarnya akan dieksekusi
sumber
Gunakan Collection Query Engine (CQEngine) . Ini adalah cara tercepat untuk melakukan ini.
Lihat juga: Bagaimana Anda meminta koleksi objek di Java (Kriteria / SQL-like)?
sumber
Beberapa jawaban bagus di sini. Saya, saya ingin menjaga agar tetap sederhana dan mudah dibaca:
sumber
Solusi pra-Java8 sederhana:
Sayangnya solusi ini tidak sepenuhnya generik, menghasilkan daftar daripada jenis koleksi yang diberikan. Juga, membawa pustaka atau fungsi penulisan yang membungkus kode ini sepertinya berlebihan bagi saya kecuali kondisinya rumit, tetapi kemudian Anda dapat menulis fungsi untuk kondisinya.
sumber
https://code.google.com/p/joquery/
Mendukung berbagai kemungkinan,
Koleksi yang diberikan,
dari jenis,
Saring
Java 7
Java 8
Juga,
Penyortiran (juga tersedia untuk Java 7)
Pengelompokan (juga tersedia untuk Java 7)
Bergabung (juga tersedia untuk Java 7)
Diberikan,
Dapat Bergabung seperti,
Ekspresi
sumber
Jawaban saya didasarkan pada hal itu dari Kevin Wong, di sini sebagai penggunaan satu-baris
CollectionUtils
dari musim semi dan ekspresi lambda Java 8 .Ini ringkas dan mudah dibaca seperti alternatif yang saya lihat (tanpa menggunakan pustaka berbasis aspek)
Spring CollectionUtils tersedia dari versi semi 4.0.2.RELEASE, dan ingat Anda membutuhkan JDK 1.8 dan level bahasa 8+.
sumber
Menggunakan
java 8
, secara khususlambda expression
, Anda dapat melakukannya cukup seperti contoh di bawah ini:di mana untuk setiap koleksi
product
di dalammyProducts
, jikaprod.price>10
, kemudian tambahkan produk ini ke daftar yang difilter baru.sumber
Saya perlu memfilter daftar tergantung pada nilai yang sudah ada dalam daftar. Misalnya, hapus semua nilai berikut yang kurang dari nilai saat ini. {2 5 3 4 7 5} -> {2 5 7}. Atau misalnya untuk menghapus semua duplikat {3 5 4 2 3 5 6} -> {3 5 4 2 6}.
Ini akan digunakan seperti ini.
sumber
Dengan jambu biji:
sumber
Di Java 8, Anda bisa langsung menggunakan metode filter ini dan kemudian melakukannya.
sumber