Bagaimana saya bisa mendapatkan elemen terakhir dari aliran atau daftar dalam kode berikut?
Dimana data.careas
a List<CArea>
:
CArea first = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal).findFirst().get();
CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.collect(Collectors.toList()).; //how to?
Seperti yang Anda lihat, mendapatkan elemen pertama, dengan pasti filter
, tidaklah sulit.
Namun mendapatkan elemen terakhir dalam satu baris adalah rasa sakit yang nyata:
- Sepertinya saya tidak bisa mendapatkannya langsung dari a
Stream
. (Ini hanya masuk akal untuk aliran yang terbatas) - Tampaknya Anda juga tidak bisa mendapatkan hal-hal seperti
first()
danlast()
dariList
antarmuka, yang sangat merepotkan.
Saya tidak melihat argumen untuk tidak menyediakan metode first()
dan last()
di List
antarmuka, karena elemen di sana, diurutkan, dan terlebih lagi ukurannya diketahui.
Tetapi sesuai jawaban aslinya: Bagaimana cara mendapatkan elemen terakhir dari sebuah finite Stream
?
Secara pribadi, ini yang paling dekat yang bisa saya dapatkan:
int lastIndex = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.mapToInt(c -> data.careas.indexOf(c)).max().getAsInt();
CArea last = data.careas.get(lastIndex);
Namun itu melibatkan, menggunakan indexOf
di setiap elemen, yang biasanya tidak Anda inginkan karena dapat mengganggu kinerja.
java
list
java-8
java-stream
skiwi
sumber
sumber
Iterables.getLast
yang membutuhkan Iterable tetapi dioptimalkan untuk digunakanList
. Hewan peliharaan yang mengesalkan adalah dia tidak punyagetFirst
. TheStream
API pada umumnya adalah mengerikan anal, menghilangkan banyak metode kenyamanan. C #'s LINQ, dengan konstrast, dengan senang hati menyediakan.Last()
dan bahkan.Last(Func<T,Boolean> predicate)
, meskipun mendukung Enumerables yang tak terbatas juga.Stream
API tidak sepenuhnya dapat dibandingkanLINQ
karena keduanya dilakukan dalam paradigma yang sangat berbeda. Itu tidak lebih buruk atau lebih baik itu hanya berbeda. Dan pasti beberapa metode tidak ada bukan karena oracle devs tidak kompeten atau jahat :)Jawaban:
Anda bisa mendapatkan elemen terakhir dengan metode Stream :: reduce . Daftar berikut berisi contoh minimal untuk kasus umum:
Implementasi ini berfungsi untuk semua aliran yang diurutkan (termasuk aliran yang dibuat dari Daftar ). Untuk aliran yang tidak berurutan , untuk alasan yang jelas tidak ditentukan elemen mana yang akan dikembalikan.
Implementasinya berfungsi untuk aliran sekuensial dan paralel . Sekilas mungkin hal itu mengejutkan, dan sayangnya dokumentasinya tidak menyatakannya secara eksplisit. Namun, ini adalah fitur aliran yang penting, dan saya mencoba menjelaskannya:
(first, second) -> second
.Dokumentasi untuk Kolektor yang terkait erat bahkan lebih eksplisit: "Untuk memastikan bahwa eksekusi sekuensial dan paralel menghasilkan hasil yang setara , fungsi kolektor harus memenuhi batasan identitas dan asosiatif ."
Kembali ke pertanyaan awal: Kode berikut menyimpan referensi ke elemen terakhir dalam variabel
last
dan melontarkan pengecualian jika aliran kosong. Kompleksitasnya linier sepanjang aliran.sumber
_
atau serupa) dalam kasus di mana Anda tidak memerlukan parameter? Jadi akan menjadi:.reduce((_, current) -> current)
jika hanya itu sintaks yang valid..reduce(($, current) -> current)
atau.reduce((__, current) -> current)
(garis bawah ganda).Stream.reduce(BinaryOperator<T>)
tidak menyebutkan jikareduce
mematuhi perintah pertemuan, dan operasi terminal bebas untuk mengabaikan perintah pertemuan bahkan jika aliran dipesan. Selain itu, kata "komutatif" tidak muncul di Stream javadocs, jadi ketiadaannya tidak memberi tahu kita banyak.reduce((a,b)->b)
menjadi solusi yang tepat untuk mendapatkan elemen terakhir (dari aliran yang teratur, tentu saja) atau tidak. Pernyataan Brian Goetz membuat satu poin, lebih lanjut dokumentasi API menyatakan bahwareduce("", String::concat)
ini adalah solusi yang tidak efisien tetapi benar untuk penggabungan string, yang menyiratkan pemeliharaan urutan pertemuan. Maksudnya adalah terkenal, dokumentasi harus menyusul.Jika Anda memiliki Koleksi (atau lebih umum Iterable) Anda dapat menggunakan Google Guava
sebagai oneliner berguna.
sumber
Iterables.getLast(() -> data.careas.stream().filter(c -> c.bbox.orientationHorizontal).iterator())
Satu liner (tidak perlu streaming;):
sumber
ArrayIndexOutOfBoundsException
.Jambu biji memiliki metode khusus untuk kasus ini:
Ini setara dengan
stream.reduce((a, b) -> b)
tetapi pencipta mengklaim itu memiliki kinerja yang jauh lebih baik.Dari dokumentasi :
Perlu disebutkan bahwa jika aliran tidak diurutkan, metode ini akan berfungsi
findAny()
.sumber
Jika Anda perlu mendapatkan jumlah N elemen terakhir. Penutupan bisa digunakan. Kode di bawah ini mempertahankan antrian eksternal dengan ukuran tetap sampai, aliran mencapai akhir.
Pilihan lainnya adalah menggunakan operasi pengurangan menggunakan identitas sebagai Antrian.
sumber
Anda juga dapat menggunakan fungsi skip () seperti di bawah ini ...
ini sangat mudah digunakan.
sumber
ArrayIndexOutOfBoundsException