2016-10-05 4 views
7

Javaストリームを使用して、リストList<A>のようなPOJOのリストを実行し、マップMap<String, Set<String>>に変換します。例えば、クラスAはJavaストリームCollectors.toMapの値がセット

されています:

class A { 
    public String name; 
    public String property; 
} 

私は以下のコードは、マップMap<String, String>に値を収集書いた:

final List<A> as = new ArrayList<>(); 
// the list as is populated ... 

// works if there are no duplicates for name 
final Map<String, String> m = as.stream().collect(Collectors.toMap(x -> x.name, x -> x.property)); 

しかし、同じで複数のPOJOがあるかもしれませんので、 name、地図の値をSetにします。すべてproperty同じキーnameの文字列は同じセットに入れる必要があります。

はどのようにこれを行うことができますか?

// how do i create a stream such that all properties of the same name get into a set under the key name 
final Map<String, Set<String>> m = ??? 

答えて

15

groupingBy正確に何をしたいん:次のように

import static java.util.stream.Collectors.*; 
... 
as.stream().collect(groupingBy((x) -> x.name, mapping((x) -> x.property, toSet()))); 
+2

小さな補正としてのSetUtils::unionを使用することができ、私はそれが輸入静的java.util.stream.Collectorsすべきだと思います*。修正 – tkja

+1

Woops、:D – Nevay

+1

あなたは、単一のラムダパラメータを括弧で囲む必要はありません。 – shmosel

0

はまた、あなたがCollectors.toMap機能 Collectors.toMap(keyMapper、valueMapper、mergeFunction)の合併機能オプションを使用することができます。

final Map<String, String> m = as.stream() 
           .collect(Collectors.toMap(
              x -> x.name, 
              x -> x.property, 
              (property1, property2) -> property1+";"+property2); 
+0

文字列ではなく、に値を収集するという質問がありました。 – splatch

0

@Nevayの答えは間違いなくgroupingByを使用して行くための正しい方法ですが、それはによっても達成可能です第三パラメータとしてmergeFunctionを追加することによって:

as.stream().collect(Collectors.toMap(x -> x.name, 
    x -> new HashSet<>(Arrays.asList(x.property)), 
    (x,y)->{x.addAll(y);return x;})); 

このコードはx.propertyとして一つの値でHashSetとしてx.nameとしてキーを持つマップ値に配列をマッピングします。重複するキー/値がある場合、3つ目のパラメータマージ関数が呼び出され、2つのHashSetがマージされます。

PS。あなたがApacheの共通ライブラリを使用する場合は、合併

関連する問題