Saya memiliki kumpulan data yang diwakili oleh aliran Java 8:
Stream<T> stream = ...;
Saya dapat melihat cara memfilternya untuk mendapatkan subset acak - misalnya
Random r = new Random();
PrimitiveIterator.OfInt coin = r.ints(0, 2).iterator();
Stream<T> heads = stream.filter((x) -> (coin.nextInt() == 0));
Saya juga bisa melihat bagaimana saya bisa mengurangi aliran ini untuk mendapatkan, misalnya, dua daftar yang mewakili dua bagian acak dari kumpulan data, dan kemudian mengubahnya kembali menjadi aliran. Tapi, adakah cara langsung untuk menghasilkan dua aliran dari yang pertama? Sesuatu seperti
(heads, tails) = stream.[some kind of split based on filter]
Terima kasih atas wawasannya.
java
java-8
java-stream
pengguna1148758
sumber
sumber
Stream
ke beberapaStream
s tanpa konversi menengah , meskipun saya pikir orang-orang yang mencapai pertanyaan ini benar-benar mencari jalan untuk mencapai sehingga terlepas dari kendala tersebut, yang merupakan jawaban Markus. Ini mungkin karena fakta bahwa pertanyaan dalam judul tidak sama dengan yang ada dalam deskripsi .Jawaban:
Tidak persis. Anda tidak bisa mendapatkan dua
Stream
dari satu; ini tidak masuk akal - bagaimana Anda beralih satu tanpa perlu menghasilkan yang lain pada saat yang sama? Streaming hanya dapat dioperasikan sekali.Namun, jika Anda ingin membuangnya ke daftar atau sesuatu, Anda bisa melakukannya
sumber
stream.collect(...)
for - for-safe dengan standarCollectors
, yang berfungsi dengan baik bahkan pada Koleksi non-thread-safe (tanpa pertikaian kunci yang disinkronkan). Jawaban terbaik oleh @MarkJeronimus.Seorang kolektor dapat digunakan untuk ini.
Collectors.partitioningBy()
pabrik.Ini akan membuat
Map
dariBoolean
keList
, dan meletakkan item dalam satu atau daftar lain berdasarkan aPredicate
.Catatan: Karena aliran perlu dikonsumsi keseluruhan, ini tidak dapat bekerja pada aliran yang tak terbatas. Dan karena aliran dikonsumsi pula, metode ini hanya menempatkan mereka di Daftar daripada membuat aliran-dengan-memori baru. Anda selalu dapat melakukan streaming daftar tersebut jika Anda membutuhkan streaming sebagai output.
Juga, tidak perlu untuk iterator, bahkan tidak dalam contoh head-only yang Anda berikan.
Collectors.groupingBy()
pabrik.Jika aliran tidak
Stream
, tetapi salah satu aliran primitif sukaIntStream
, maka.collect(Collectors)
metode ini tidak tersedia. Anda harus melakukannya dengan cara manual tanpa pabrik pengumpul. Implementasinya terlihat seperti ini:[Contoh 2.0 sejak 2020-04-16]
Dalam contoh ini saya menginisialisasi ArrayLists dengan ukuran penuh dari koleksi awal (jika ini diketahui sama sekali). Ini mencegah mengubah ukuran peristiwa bahkan dalam skenario terburuk, tetapi berpotensi dapat melahap ruang 2 * N * T (N = jumlah elemen awal, T = jumlah utas). Untuk menukar ruang untuk kecepatan, Anda dapat meninggalkannya atau menggunakan tebakan terbaik Anda, seperti jumlah elemen tertinggi yang diharapkan dalam satu partisi (biasanya lebih dari N / 2 untuk pemisahan seimbang).
Saya harap saya tidak menyinggung siapa pun dengan menggunakan metode Java 9. Untuk versi Java 8, lihat pada edit history.
sumber
stream.boxed().collect(...);
! Ini akan melakukan seperti yang diiklankan: konversi primitifIntStream
keStream<Integer>
versi kotak .(map, x) -> { boolean partition = p.test(x); List<Integer> list = map.get(partition); list.add(x); }
Anda cukup menggunakan(map, x) -> map.get(p.test(x)).add(x)
. Lebih jauh, saya tidak melihat alasan mengapacollect
operasi ini tidak aman. Ia bekerja persis seperti yang seharusnya bekerja dan sangat erat dengan caraCollectors.partitioningBy(p)
kerjanya. Tapi saya akan menggunakanIntPredicate
bukanPredicate<Integer>
saat tidak menggunakanboxed()
, untuk menghindari tinju dua kali.Saya menemukan pertanyaan ini pada diri saya dan saya merasa bahwa aliran bercabang memiliki beberapa kasus penggunaan yang dapat membuktikan valid. Saya menulis kode di bawah ini sebagai konsumen sehingga tidak melakukan apa pun tetapi Anda dapat menerapkannya pada fungsi dan hal lain yang mungkin Anda temui.
Sekarang implementasi kode Anda bisa seperti ini:
sumber
Sayangnya, apa yang Anda minta langsung disukai di JavaDoc of Stream :
Anda dapat mengatasi ini menggunakan
peek
atau metode lain jika Anda benar-benar menginginkan jenis perilaku itu. Dalam hal ini, yang harus Anda lakukan adalah alih-alih mencoba untuk mundur dua aliran dari sumber Stream asli yang sama dengan filter forking, Anda akan menduplikasi aliran Anda dan memfilter masing-masing duplikat dengan tepat.Namun, Anda mungkin ingin mempertimbangkan kembali jika a
Stream
adalah struktur yang sesuai untuk kasus penggunaan Anda.sumber
List<Stream> forkStream(Stream s)
tetapi aliran yang dihasilkan saya setidaknya akan sebagian didukung oleh koleksi dan tidak secara langsung oleh aliran yang mendasarinya, sebagai lawan untuk mengatakanfilter
yang bukan operasi aliran terminal.Ini bertentangan dengan mekanisme umum Stream. Katakanlah Anda dapat membagi Stream S0 ke Sa dan Sb seperti yang Anda inginkan. Melakukan operasi terminal apa pun, katakanlah
count()
, pada Sa akan selalu "mengkonsumsi" semua elemen di S0. Karena itu Sb kehilangan sumber datanya.Sebelumnya, Stream punya
tee()
metode, saya pikir, yang menduplikasi aliran menjadi dua. Sudah dihapus sekarang.Aliran memiliki metode mengintip (), Anda mungkin dapat menggunakannya untuk mencapai kebutuhan Anda.
sumber
peek
persis seperti dulutee
.tidak persis, tetapi Anda mungkin dapat mencapai apa yang Anda butuhkan dengan memohon
Collectors.groupingBy()
. Anda membuat Koleksi baru, dan kemudian dapat instantiate stream pada koleksi baru itu.sumber
Ini adalah jawaban yang paling buruk yang bisa kudapat.
Ini mengambil aliran bilangan bulat dan membaginya menjadi 5. Untuk yang lebih besar dari 5 itu hanya menyaring bilangan genap dan menempatkannya dalam daftar. Selebihnya bergabung dengan mereka dengan |.
output:
Tidak ideal karena mengumpulkan segala sesuatu ke dalam koleksi perantara yang memecah aliran (dan memiliki terlalu banyak argumen!)
sumber
Saya menemukan pertanyaan ini sambil mencari cara untuk memfilter elemen tertentu dari aliran dan mencatatnya sebagai kesalahan. Jadi saya tidak benar-benar perlu untuk membagi aliran sebanyak melampirkan tindakan penghentian prematur untuk predikat dengan sintaksis yang tidak mengganggu. Inilah yang saya pikirkan:
sumber
Versi lebih pendek yang menggunakan Lombok
sumber
Bagaimana tentang:
sumber