Apakah ada cara ringkas untuk beralih di atas aliran sementara memiliki akses ke indeks di arus?
String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
List<String> nameList;
Stream<Integer> indices = intRange(1, names.length).boxed();
nameList = zip(indices, stream(names), SimpleEntry::new)
.filter(e -> e.getValue().length() <= e.getKey())
.map(Entry::getValue)
.collect(toList());
yang tampaknya agak mengecewakan dibandingkan dengan contoh LINQ yang diberikan di sana
string[] names = { "Sam", "Pamela", "Dave", "Pascal", "Erik" };
var nameList = names.Where((c, index) => c.Length <= index + 1).ToList();
Apakah ada cara yang lebih ringkas?
Lebih lanjut tampaknya zip telah dipindahkan atau dihapus ...
java
java-8
java-stream
Graeme Moss
sumber
sumber
intRange()
? Belum menemukan metode ini di Java 8 sampai sekarang.IntStream.rangeClosed(x, y)
.List<String> allCities = map.values().stream().flatMap(list -> list.stream()).collect(Collectors.toList());
zip
telah dihapus, bersama dengan aliran dua nilai eksperimental dengan berbagai cara disebutBiStream
atauMapStream
. Masalah utama adalah bahwa untuk melakukan ini secara efektif, Java benar-benar membutuhkan tipe (atau tuple) yang diketik secara struktural. Karena tidak memiliki satu, mudah untuk membuat kelas Pair atau Tuple generik - sudah dilakukan berkali-kali - tetapi semuanya terhapus dengan tipe yang sama.Jawaban:
Cara terbersih adalah mulai dari aliran indeks:
Daftar yang dihasilkan hanya berisi "Erik".
Salah satu alternatif yang terlihat lebih akrab ketika Anda terbiasa dengan loop adalah mempertahankan counter ad hoc menggunakan objek yang bisa berubah, misalnya
AtomicInteger
:Perhatikan bahwa menggunakan metode terakhir pada aliran paralel dapat pecah karena item tidak perlu diproses "dalam urutan" .
sumber
public static <T> Stream<Tuple2<Integer, T>> zipWithIndex(Stream<T> stream) { final AtomicInteger index = new AtomicInteger(); final Function<T, Tuple2<Integer, T>> zipper = e -> Tuples.of(index.getAndIncrement(), e); if (stream.isParallel()) { return stream.sequential().map(zipper).parallel(); } else { return stream.map(zipper); } }
parallel
atausequential
yang dihormati ketika operasi terminal dimulai.API Java 8 stream tidak memiliki fitur untuk mendapatkan indeks elemen stream serta kemampuan untuk zip stream bersama. Ini sangat disayangkan, karena membuat aplikasi tertentu (seperti tantangan LINQ) lebih sulit daripada yang seharusnya.
Namun, sering ada penyelesaian masalah. Biasanya ini dapat dilakukan dengan "mengarahkan" aliran dengan rentang integer, dan mengambil keuntungan dari fakta bahwa elemen asli sering dalam array atau dalam koleksi yang dapat diakses oleh indeks. Misalnya, masalah Tantangan 2 dapat diselesaikan dengan cara ini:
Seperti yang saya sebutkan di atas, ini mengambil keuntungan dari fakta bahwa sumber data (array nama) secara langsung dapat diindeks. Jika tidak, teknik ini tidak akan berhasil.
Saya akan mengakui bahwa ini tidak memenuhi maksud Tantangan 2. Meskipun demikian, ini menyelesaikan masalah dengan cukup efektif.
EDIT
Contoh kode saya sebelumnya digunakan
flatMap
untuk memadukan operasi filter dan pemetaan, tetapi ini rumit dan tidak memberikan keuntungan. Saya telah memperbarui contoh per komentar dari Holger.sumber
IntStream.range(0, names.length).filter(i->names[i].length()<=i).mapToObj(i->names[i])
? Itu bekerja tanpa tinju ...flatMap
?flatMap
karena ini semacam sekering operasi penyaringan dan pemetaan menjadi satu operasi, tetapi ini benar-benar tidak memberikan keuntungan. Saya akan mengedit contohnya.Stream.of( names ).filter( n -> n.length() <= 1).collect( Collectors.toList() );
Kurang unboxing, dan alokasi memori lebih sedikit; karena kami tidak membuat aliran rentang lagi.Sejak jambu 21, Anda bisa menggunakannya
Contoh (dari dokumen resmi ):
sumber
Saya telah menggunakan solusi berikut dalam proyek saya. Saya pikir ini lebih baik daripada menggunakan objek yang bisa berubah atau rentang integer.
sumber
StreamSupport.stream()
dan iterator khusus.Selain protonpack, SeOO jOOλ menyediakan fungsionalitas ini (dan oleh ekstensi library yang membangunnya seperti cyclops-react , saya adalah penulis perpustakaan ini).
Seq juga mendukung hanya Seq.of (nama) dan akan membangun JDK Stream di bawah selimut.
Persamaan reaksi sederhana akan terlihat seperti
Versi reaksi sederhana lebih disesuaikan untuk pemrosesan asinkron / bersamaan.
sumber
Hanya untuk kelengkapan, inilah solusi yang melibatkan pustaka StreamEx saya :
Di sini kami membuat
EntryStream<Integer, String>
yang memperluasStream<Entry<Integer, String>>
dan menambahkan beberapa operasi tertentu sepertifilterKeyValue
atauvalues
. JugatoList()
shortcut digunakan.sumber
.forEach(entry -> {})
?.forKeyValue((key, value) -> {})
.Saya menemukan solusi di sini ketika Stream dibuat dari daftar atau array (dan Anda tahu ukurannya). Tetapi bagaimana jika Stream dengan ukuran yang tidak diketahui? Dalam hal ini coba varian ini:
Pemakaian:
sumber
Dengan Daftar Anda dapat mencoba
Keluaran:
sumber
Tidak ada cara untuk beralih
Stream
sementara memiliki akses ke indeks karenaStream
tidak seperti apa punCollection
. AStream
hanyalah jalur pipa untuk membawa data dari satu tempat ke tempat lain, sebagaimana dinyatakan dalam dokumentasi :Tidak ada penyimpanan. Aliran bukanlah struktur data yang menyimpan elemen; sebaliknya, mereka membawa nilai-nilai dari sumber (yang bisa berupa struktur data, generator, saluran IO, dll) melalui pipa operasi komputasi.
Tentu saja, saat Anda mengisyaratkan pertanyaan Anda, Anda selalu dapat mengonversikannya
Stream<V>
menjadiCollection<V>
, seperti aList<V>
, di mana Anda akan memiliki akses ke indeks.sumber
Dengan https://github.com/poetix/protonpack Anda dapat melakukannya zip:
sumber
Jika Anda tidak keberatan menggunakan perpustakaan pihak ketiga, Eclipse Collections telah
zipWithIndex
danforEachWithIndex
tersedia untuk digunakan di banyak jenis. Berikut adalah serangkaian solusi untuk tantangan ini baik untuk tipe JDK dan tipe Eclipse CollectionszipWithIndex
.Inilah solusi menggunakan
forEachWithIndex
sebagai gantinya.Jika Anda mengubah lambda ke kelas batin anonim di atas, maka semua contoh kode ini akan berfungsi di Java 5 - 7 juga.
Catatan: Saya pengendara untuk Eclipse Collections
sumber
Jika Anda menggunakan Vavr (sebelumnya dikenal sebagai Javaslang), Anda dapat memanfaatkan metode khusus:
Jika kami mencetak konten, kami akan melihat sesuatu yang menarik:
Ini karena
Streams
malas dan kami tidak memiliki petunjuk tentang item berikutnya dalam arus.sumber
Jika Anda mencoba untuk mendapatkan indeks berdasarkan predikat, coba ini:
Jika Anda hanya peduli dengan indeks pertama:
Atau jika Anda ingin menemukan beberapa indeks:
Tambahkan
.orElse(-1);
jika Anda ingin mengembalikan nilai jika tidak menemukannya.sumber
Berikut ini kode dari AbacusUtil
Pengungkapan : Saya pengembang AbacusUtil.
sumber
Anda dapat menggunakan
IntStream.iterate()
untuk mendapatkan indeks:Ini hanya berfungsi untuk Java 9 ke atas di Java 8 Anda dapat menggunakan ini:
sumber
Anda dapat membuat kelas dalam statis untuk merangkum pengindeks seperti yang perlu saya lakukan dalam contoh di bawah ini:
sumber
Pertanyaan ini ( Cara Streaming untuk mendapatkan indeks boolean pencocokan elemen pertama ) telah menandai pertanyaan saat ini sebagai duplikat, jadi saya tidak bisa menjawabnya di sana; Saya menjawabnya di sini.
Berikut ini adalah solusi umum untuk mendapatkan indeks yang cocok yang tidak memerlukan perpustakaan eksternal.
Jika Anda punya daftar.
Dan menyebutnya seperti ini:
Dan jika menggunakan koleksi, coba yang ini.
sumber
Salah satu cara yang mungkin adalah dengan mengindeks setiap elemen pada aliran:
Menggunakan kelas anonim di sepanjang aliran tidak digunakan dengan baik sementara sangat berguna.
sumber
Anda tidak perlu
map
harusitu adalah lambda terdekat dengan contoh LINQ:
sumber
OUTPUT: Sam, Pamela, Dave, Pascal, Erik
Untuk Mengumpulkan dalam Daftar:
sumber
List
satu elemen yang mengandung Erik .Seperti yang dikatakan jean-baptiste-yunès, jika aliran Anda didasarkan pada Daftar java kemudian menggunakan AtomicInteger dan metode incrementementAndGet adalah solusi yang sangat baik untuk masalah dan integer yang dikembalikan sesuai dengan indeks dalam Daftar asli selama Anda jangan gunakan aliran paralel.
sumber
Jika Anda memerlukan indeks di forEach maka ini menyediakan cara.
Kemudian gunakan sebagai berikut.
sumber