Saya tahu cara "mengubah" Java sederhana List
dari Y
-> Z
, yaitu:
List<String> x;
List<Integer> y = x.stream()
.map(s -> Integer.parseInt(s))
.collect(Collectors.toList());
Sekarang pada dasarnya saya ingin melakukan hal yang sama dengan Peta, yaitu:
INPUT:
{
"key1" -> "41", // "41" and "42"
"key2" -> "42 // are Strings
}
OUTPUT:
{
"key1" -> 41, // 41 and 42
"key2" -> 42 // are Integers
}
Solusinya tidak terbatas pada String
-> Integer
. Sama seperti pada List
contoh di atas, saya ingin memanggil metode apa pun (atau konstruktor).
java
mapreduce
java-8
java-stream
collectors
Benjamin M
sumber
sumber
e -> e.getKey()
denganMap.Entry::getKey
. Tapi itu masalah selera / gaya pemrograman.Berikut adalah beberapa variasi jawaban Sotirios Delimanolis , yang cukup baik untuk memulai dengan (+1). Pertimbangkan yang berikut ini:
Beberapa poin di sini. Pertama adalah penggunaan wildcard dalam obat generik; ini membuat fungsinya agak lebih fleksibel. Wildcard akan diperlukan jika, misalnya, Anda ingin peta keluaran memiliki kunci yang merupakan superclass dari kunci peta input:
(Ada juga contoh untuk nilai-nilai peta, tetapi ini benar-benar dibuat-buat, dan saya akui bahwa memiliki wildcard terbatas untuk Y hanya membantu dalam kasus tepi.)
Poin kedua adalah bahwa alih-alih menjalankan streaming di atas peta input
entrySet
, saya malah menjalankannya di ataskeySet
. Ini membuat kode sedikit lebih bersih, saya pikir, dengan biaya harus mengambil nilai dari peta alih-alih dari entri peta. Kebetulan, saya awalnya memilikikey -> key
argumen pertamatoMap()
dan ini gagal dengan kesalahan inferensi jenis karena beberapa alasan. Mengubahnya(X key) -> key
berfungsi, seperti yang terjadiFunction.identity()
.Variasi lain adalah sebagai berikut:
Ini menggunakan
Map.forEach()
bukannya stream. Ini bahkan lebih sederhana, saya pikir, karena itu dibagikan kepada kolektor, yang agak canggung untuk digunakan dengan peta. Alasannya adalah bahwaMap.forEach()
memberikan kunci dan nilai sebagai parameter terpisah, sedangkan aliran hanya memiliki satu nilai - dan Anda harus memilih apakah akan menggunakan kunci atau entri peta sebagai nilai itu. Di sisi minusnya, ini tidak memiliki kekayaan, aliran kebaikan dari pendekatan lain. :-)sumber
Function.identity()
mungkin terlihat keren tetapi karena solusi pertama membutuhkan pencarian peta / hash untuk setiap entri sedangkan semua solusi lainnya tidak, saya tidak akan merekomendasikan hal ini.Solusi generik seperti itu
Contoh
sumber
Fungsi Guava
Maps.transformValues
adalah apa yang Anda cari, dan berfungsi baik dengan ekspresi lambda:sumber
java.util.Function
, Anda memiliki dua opsi. 1. Hindari masalah dengan menggunakan lambda untuk membiarkan inferensi tipe Java mengatasinya. 2. Gunakan referensi metode seperti javaFunction :: apply untuk menghasilkan lambda baru yang dapat ditemukan oleh tipe inferensi.Apakah benar-benar harus 100% fungsional dan lancar? Jika tidak, bagaimana dengan ini, yang singkatnya:
( jika Anda dapat hidup dengan rasa malu dan bersalah karena menggabungkan aliran dengan efek samping )
sumber
Pustaka StreamEx saya yang meningkatkan API aliran standar menyediakan
EntryStream
kelas yang lebih sesuai untuk mengubah peta:sumber
Alternatif yang selalu ada untuk tujuan pembelajaran adalah membangun kolektor khusus Anda melalui Collector.of () toMap () JDK kolektor di sini singkat (+1 di sini ).
sumber
map2.entrySet().forEach(entry -> { if (map1.containsKey(entry.getKey())) { map1.get(entry.getKey()).merge(entry.getValue()); } else { map1.put(entry.getKey(),entry.getValue()); } }); return map1
atau nilai-nilai akan hilang ketika dikurangi.Jika Anda tidak keberatan menggunakan perpustakaan pihak ketiga, lib -siklop-reaksi saya memiliki ekstensi untuk semua jenis Koleksi JDK , termasuk Peta . Kami hanya dapat mengubah peta secara langsung menggunakan operator 'peta' (secara default peta bertindak berdasarkan nilai-nilai di peta).
bimap dapat digunakan untuk mengubah kunci dan nilai pada saat yang sama
sumber
Solusi deklaratif dan sederhana adalah:
yourMutableMap.replaceAll ((key, val) -> return_value_of_bi_your_function); Nb. Ketahuilah bahwa Anda memodifikasi kondisi peta Anda. Jadi ini mungkin bukan yang Anda inginkan.
Ceria untuk: http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/
sumber