Untuk pertanyaan spesifik tentang menghasilkan kebalikan IntStream
, coba sesuatu seperti ini:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Ini menghindari tinju dan penyortiran.
Untuk pertanyaan umum tentang cara membalikkan aliran jenis apa pun, saya tidak tahu ada cara yang "tepat". Ada beberapa cara yang bisa saya pikirkan. Keduanya akhirnya menyimpan elemen stream. Saya tidak tahu cara untuk membalikkan aliran tanpa menyimpan elemen.
Cara pertama ini menyimpan elemen ke dalam array dan membacanya ke aliran dalam urutan terbalik. Perhatikan bahwa karena kita tidak tahu tipe runtime dari elemen stream, kita tidak bisa mengetikkan array dengan benar, membutuhkan cetakan yang tidak dicentang.
@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
Object[] temp = input.toArray();
return (Stream<T>) IntStream.range(0, temp.length)
.mapToObj(i -> temp[temp.length - i - 1]);
}
Teknik lain menggunakan kolektor untuk mengumpulkan item ke dalam daftar terbalik. Ini melakukan banyak penyisipan di bagian depanArrayList
objek, jadi ada banyak penyalinan yang terjadi.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Mungkin untuk menulis kolektor pembalikan yang jauh lebih efisien menggunakan semacam struktur data yang disesuaikan.
UPDATE 2016-01-29
Karena pertanyaan ini telah mendapatkan sedikit perhatian baru-baru ini, saya pikir saya harus memperbarui jawaban saya untuk menyelesaikan masalah dengan memasukkan di depan ArrayList
. Ini akan sangat tidak efisien dengan sejumlah besar elemen, yang membutuhkan penyalinan O (N ^ 2).
Lebih baik menggunakan yang ArrayDeque
sebaliknya, yang secara efisien mendukung penyisipan di bagian depan. Kerutan kecil adalah bahwa kita tidak dapat menggunakan bentuk tiga-arg Stream.collect()
; itu membutuhkan isi dari arg kedua digabungkan ke dalam arg pertama, dan tidak ada operasi massal "add-all-at-front" aktif Deque
. Sebagai gantinya, kita gunakan addAll()
untuk menambahkan konten dari arg pertama ke akhir yang kedua, dan kemudian kita mengembalikan yang kedua. Ini mengharuskan menggunakan Collector.of()
metode pabrik.
Kode lengkapnya adalah ini:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Hasilnya adalah Deque
bukannya List
, tetapi itu seharusnya tidak menjadi masalah, karena dapat dengan mudah diulangi atau dialirkan dalam urutan yang sekarang terbalik.
IntStream
tidak memiliki.sorted(Comparator)
metode; Anda harus pergi melaluiStream<Integer>
pertama dan reverse sana sebelum menghasilkan sebuahIntStream