Diberikan aliran seperti { 0, 1, 2, 3, 4 }
,
bagaimana cara paling elegan mengubahnya menjadi bentuk tertentu:
{ new Pair(0, 1), new Pair(1, 2), new Pair(2, 3), new Pair(3, 4) }
(dengan asumsi, tentu saja, saya telah mendefinisikan kelas Pair)?
Sunting: Ini bukan hanya tentang int atau aliran primitif. Jawabannya harus umum untuk aliran jenis apa pun.
java
java-8
java-stream
Aleksandr Dubinsky
sumber
sumber
list.stream().map(i -> new Pair(i, i+1));
Map.Entry
sebagai kelas Pair. (Memang, beberapa mungkin menganggap itu peretasan, tetapi menggunakan kelas bawaan berguna.)Jawaban:
Perpustakaan StreamEx saya yang memperluas aliran standar menyediakan
pairMap
metode untuk semua jenis aliran. Untuk aliran primitif, ini tidak mengubah jenis aliran, tetapi dapat digunakan untuk membuat beberapa perhitungan. Penggunaan paling umum adalah untuk menghitung perbedaan:Untuk aliran objek, Anda dapat membuat jenis objek lainnya. Perpustakaan saya tidak menyediakan struktur data baru yang terlihat oleh pengguna seperti
Pair
(itu adalah bagian dari konsep perpustakaan). Namun jika Anda memilikiPair
kelas Anda sendiri dan ingin menggunakannya, Anda dapat melakukan hal berikut:Atau jika Anda sudah memiliki beberapa
Stream
:Fungsionalitas ini diimplementasikan menggunakan pemisah khusus . Ini memiliki overhead yang cukup rendah dan dapat diparalelkan dengan baik. Tentu saja ini berfungsi dengan sumber aliran apa pun, bukan hanya daftar / larik akses acak seperti banyak solusi lainnya. Dalam banyak pengujian, alat ini bekerja dengan sangat baik. Berikut adalah patokan JMH di mana kita menemukan semua nilai input sebelum nilai yang lebih besar menggunakan pendekatan yang berbeda (lihat pertanyaan ini ).
sumber
StreamEx
mengimplementasikanIterable
! Hore!)Stream
aStreamEx
?StreamEx.of(stream)
. Ada metode statis lain yang mudah digunakan untuk membuat aliran dariCollection
, larikReader
,, dll. Diedit jawabannya.pairMap
dipesan pada aliran berurutan? Sebenarnya, saya ingin memiliki forPairsOrdered (), tetapi karena tidak ada metode seperti itu, dapatkah saya mensimulasikannya?stream.ordered().forPairs()
ataustream().pairMap().forEachOrdered()
?pairMap
adalah operasi perantara dengan fungsi mapper stateless non-interferensi, pengurutan tidak ditentukan untuknya dengan cara yang sama seperti untuk sederhanamap
. TidakforPairs
diurutkan menurut spesifikasi, tetapi operasi yang tidak diurutkan secara de-facto diurutkan untuk streaming berurutan. Akan lebih baik jika Anda merumuskan masalah asli Anda sebagai pertanyaan stackoverflow terpisah untuk memberikan lebih banyak konteks.Pustaka aliran Java 8 terutama ditujukan untuk memisahkan aliran menjadi potongan yang lebih kecil untuk pemrosesan paralel, sehingga tahapan pipeline stateful sangat terbatas, dan melakukan hal-hal seperti mendapatkan indeks elemen aliran saat ini dan mengakses elemen aliran yang berdekatan tidak didukung.
Cara khas untuk memecahkan masalah ini, dengan beberapa keterbatasan, tentu saja, adalah dengan mengarahkan aliran dengan indeks dan mengandalkan nilai yang diproses dalam beberapa struktur data akses-acak seperti ArrayList tempat elemen dapat diambil. Jika nilainya masuk
arrayList
, seseorang dapat menghasilkan pasangan seperti yang diminta dengan melakukan sesuatu seperti ini:Tentu saja batasannya adalah input tidak bisa menjadi aliran yang tak terbatas. Pipeline ini bisa dijalankan secara paralel.
sumber
arrayList
) sebenarnya adalah sebuah koleksi, itulah mengapa saya tidak menandainya sebagai jawaban. (Tapi selamat atas lencana emas Anda!)Ini tidak elegan, ini adalah solusi hackish, tetapi berfungsi untuk aliran tak terbatas
Sekarang Anda dapat membatasi streaming sesuai durasi yang Anda inginkan
PS Saya berharap ada solusi yang lebih baik, seperti clojure
(partition 2 1 stream)
sumber
parallelStream
dokumen: "Untuk menjaga perilaku yang benar, parameter perilaku ini tidak boleh mengganggu, dan dalam banyak kasus harus tanpa kewarganegaraan"Saya telah menerapkan pembungkus spliterator yang mengambil setiap
n
elemenT
dari spliterator asli dan menghasilkanList<T>
:Metode berikut dapat digunakan untuk membuat aliran berurutan:
Penggunaan sampel:
sumber
List<E>
elemen. Setiap daftar berisin
elemen yang berurutan dari aliran asli. Periksa sendiri;)(partition size step)
fungsi dan ini tentang cara terbaik untuk mendapatkannya.ArrayDeque
untuk kinerja, daripadaLinkedList
.Anda dapat melakukan ini dengan metode Stream.reduce () (Saya belum melihat jawaban lain menggunakan teknik ini).
sumber
Anda dapat melakukan ini di cyclops-react (saya berkontribusi pada perpustakaan ini), menggunakan operator geser.
Atau
Dengan asumsi konstruktor Pair dapat menerima Koleksi dengan 2 elemen.
Jika Anda ingin mengelompokkan dengan 4, dan kenaikan 2 itu juga didukung.
Metode statis setara untuk membuat tampilan geser di atas java.util.stream.Stream juga disediakan di kelas StreamUtils cyclops-streams .
Catatan: - untuk operasi single-threaded, ReactiveSeq akan lebih sesuai. LazyFutureStream memperluas ReactiveSeq tetapi terutama ditujukan untuk penggunaan bersamaan / paralel (ini adalah Stream of Futures).
LazyFutureStream memperluas ReactiveSeq yang memperluas Seq dari jOOλ yang mengagumkan (yang memperluas java.util.stream.Stream), sehingga solusi yang diberikan Lukas juga akan berfungsi dengan salah satu jenis Stream. Bagi siapa pun yang tertarik, perbedaan utama antara operator jendela / geser adalah daya relatif / kompleksitas yang jelas trade off dan kesesuaian untuk digunakan dengan aliran tak terbatas (geser tidak menghabiskan aliran, tetapi menyangga saat mengalir).
sumber
The proton-pack perpustakaan menyediakan functionnality berjendela. Diberikan kelas Pair dan Stream, Anda dapat melakukannya seperti ini:
Sekarang
pairs
aliran tersebut berisi:sumber
st
dua kali! Bisakah pustaka ini menyelesaikan masalah menggunakan aliran tunggal?windowed
Fungsinya telah ditambahkan! Lihat edit.Menemukan pasangan yang berurutan
Jika Anda ingin menggunakan pustaka pihak ketiga dan tidak membutuhkan paralelisme, maka jOOλ menawarkan fungsi jendela gaya SQL sebagai berikut
Menghasilkan
The
lead()
Fungsi mengakses nilai berikutnya dalam rangka traversal dari jendela.Menemukan tripel / quadruples / n-tuple yang berurutan
Sebuah pertanyaan di komentar meminta solusi yang lebih umum, di mana tidak berpasangan tetapi n-tupel (atau mungkin daftar) harus dikumpulkan. Inilah pendekatan alternatif:
Menghasilkan daftar daftar
Tanpa itu
filter(w -> w.count() == n)
, hasilnya pastiPenafian: Saya bekerja untuk perusahaan di belakang jOOλ
sumber
w.lead().lead()
?tuple(w.value(), w.lead(1), w.lead(2))
akan menjadi pilihan. Saya telah memperbarui jawaban saya dengan solusi yang lebih umum untuklength = n
.window()
bukan operasi malas yang mengumpulkan seluruh aliran input menjadi beberapa koleksi perantara, kemudian membuat aliran baru darinya?Comparator
digunakan untuk menyusun ulang jendela), maka pengoptimalan seperti ini dapat dilakukan, dan kemungkinan besar akan diterapkan di masa mendatang.Streams.zip(..)
tersedia di Jambu biji , bagi yang bergantung padanya.Contoh:
sumber
Kita bisa menggunakan RxJava ( pustaka ekstensi reaktif yang sangat kuat )
sumber
Observable.zip(obs, obs.skip(1), pair->{...})
sampai sekarang! Saya tidak tahuObservable.buffer
memiliki versi dengan langkah (dan saya terbiasa denganzip
trik dari python). +1Operasi ini pada dasarnya stateful, jadi bukan apa yang harus diselesaikan oleh aliran - lihat bagian "Perilaku Tanpa Kewarganegaraan" di javadoc :
Salah satu solusinya di sini adalah memperkenalkan status dalam aliran Anda melalui penghitung eksternal, meskipun ini hanya akan berfungsi dengan aliran berurutan.
sumber
Stream
:! = "Lambdas".StreamEx
perpustakaan juga menemukan baik dan bisa menjadi jawaban sendiri. Komentar saya tentang "streams! = Lambdas" mengacu pada Anda yang menyatakan "Operasi pada dasarnya stateful jadi bukan apa yang lambda maksudkan untuk dipecahkan." Saya pikir Anda bermaksud menggunakan kata "aliran".Dalam kasus Anda, saya akan menulis IntFungsi kustom saya yang melacak int terakhir yang dilewati dan menggunakannya untuk memetakan IntStream asli.
sumber
Untuk menghitung perbedaan berturut-turut dalam waktu (nilai-x) dari deret waktu, saya menggunakan metode
stream
'scollect(...)
:Di mana DifferenceCollector terlihat seperti ini:
Anda mungkin dapat memodifikasi ini agar sesuai dengan kebutuhan Anda.
sumber
Saya akhirnya menemukan cara untuk mengelabui Stream.reduce agar dapat menangani pasangan nilai dengan rapi; Ada banyak kasus penggunaan yang membutuhkan fasilitas ini yang tidak muncul secara alami di JDK 8:
Trik yang saya gunakan adalah return right; pernyataan.
sumber
reduce
membuat jaminan yang cukup untuk bekerja.Solusi elegan adalah menggunakan zip . Sesuatu seperti:
Ini cukup ringkas dan elegan, namun menggunakan daftar sebagai masukan. Sumber aliran tak terbatas tidak dapat diproses dengan cara ini.
Masalah lain (yang lebih merepotkan) adalah bahwa zip bersama dengan seluruh kelas Stream akhir-akhir ini telah dihapus dari API. Kode di atas hanya bekerja dengan b95 atau rilis yang lebih lama. Jadi dengan JDK terbaru saya akan mengatakan tidak ada solusi gaya FP yang elegan dan saat ini kami hanya bisa berharap bahwa dalam beberapa cara zip akan diperkenalkan kembali ke API.
sumber
zip
telah dihapus. Saya tidak ingat semua apa yang ada diStreams
kelas, tapi beberapa hal yang telah bermigrasi menjadi metode statis padaStream
antarmuka, dan ada jugaStreamSupport
danStream.Builder
kelas.zip
? Alasan apa pun yang mungkin ditemukan tidak membenarkan pembunuhanzip
.Ini masalah yang menarik. Apakah percobaan hybrid saya di bawah ada gunanya?
Saya yakin ini tidak cocok untuk pemrosesan paralel, dan karenanya dapat didiskualifikasi.
sumber
Stream
, bukan aList
. Tentu saja, kami juga dapat mencabut iterator dari Stream, jadi ini mungkin solusi yang valid. Namun demikian, ini adalah pendekatan asli.Seperti yang telah diamati orang lain, ada, karena sifat masalah, beberapa keadaan yang diperlukan.
Saya dihadapkan pada masalah serupa, di mana saya menginginkan apa yang pada dasarnya adalah fungsi LEAD Oracle SQL. Upaya saya untuk menerapkannya ada di bawah ini.
sumber
Anda dapat mencapainya dengan menggunakan antrian terbatas untuk menyimpan elemen yang mengalir melalui aliran (yang mendasarkan pada ide yang saya jelaskan secara rinci di sini: Apakah mungkin untuk mendapatkan elemen berikutnya di Stream? )
Contoh di bawah ini pertama kali mendefinisikan instance kelas BoundedQueue yang akan menyimpan elemen melalui aliran (jika Anda tidak menyukai gagasan untuk memperluas LinkedList, lihat tautan yang disebutkan di atas untuk pendekatan alternatif dan yang lebih umum). Nanti Anda tinggal menggabungkan dua elemen berikutnya ke dalam contoh Pair:
sumber
Saya setuju dengan @aepurniet tetapi peta Anda harus menggunakan mapToObj
sumber
Jalankan
for
loop yang berjalan dari 0 kelength-1
streaming Andasumber