2017-08-22 3 views
1

私はマップを含む地図を持っています。 マップ> マップのすべてのエントリについて、特定のキーの合計を計算します。ラムダで使用される変数は、合計を計算する際に最終的または最終的な最終値である必要がありますか?

例えば、私のマップは、このようなものです:

Key1 Key2 Value 
A  Z  10.10 
B  Z  40.10 
C  Y  20.10 

私はこのケースでは、私はキー1 -Cとして50.20を取得したいので、基本的にはBに等しいすべてのKEY2の合計を計算しますkey2がありませんZ

私はJava 8を使用してこれを実行しようとしています。どのように合計を集めるべきか分かりません。

double sum = 0; 
myMap.forEach((key1, key2) -> { 
    sum += key2.get("Z"); 
}); 

しかし、ラムダの値は最終的な値でなければならないというエラーが表示されます。

+5

'map.values()ストリーム()mapToDouble(X - > x.get(「Z。 "))。sum()' – Misha

+0

あなたが得るエラーが予想されます。ラムダ内から 'sum'にアクセスするには、最終的なものでなければなりません。ラムダ内で最終的なものではないものは参照できません。 – Tavo

答えて

3

匿名の内部クラスまたはLambdaで使用されるすべての外部変数は、final or effectively final(決して再割り当てされない最終的な変数)である必要があります。

あなたの解決策では、古典的な命令的解決策を機能的な解決策で修正しようとしています。

慣用のJava-8のアプローチは、ストリームAPIを使用することです:

map.values().stream() 
    .map(x -> x.get("Z")) 
    .reduce(0, Double::sum); 

またはdoubleのための専門Stream利用:

​​

が正しくエッジケースを処理することを忘れないでくださいを。これは、 "Z"キーに関連付けられた値がない場合には爆発的になります。

+0

マップの前にフィルターを適用して、「Z」キーが存在することを確認してください。 –

1

ストリームを使用できます。

myMap.entrySet().stream() 
       .filter(entry -> entry.getValue().equals(Z)) 
       .map(entry -> entry.getValue()) 
       .mapToDouble(v -> v.get("Z")) 
       .sum() 

私はあなたのデータ構造について確認していないので、これは少し作業が必要になる場合がありますが、私はあなたのアイデアを得る願っています:その方法は、あなたも、中間の操作を使用することができます。

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

あなたはそれを変更することはできません範囲内のローカル変数を変更しようとするので、あなたのアプローチは、動作しません。 http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html

tl; drラムダボディのローカル変数を変更することはできません。

0

ストリームで正しく(あなたの例)行う方法を教えてください。 (でも、JDKのソース内の配列のラッパーが必要とされている場所がある)けれども時にはそれは現実的ではありません。

double [] sum = {0}; 
myMap.forEach((key1, key2) -> { 
    sum[0] += key2.get("Z"); 
}); 
関連する問題