Java 8(まだ学習中))にあまり馴染みがなく、ストリームを使用して以下のコードに相当するものを見つけることができるかどうかを確認しています。
以下のコードは主に、Stringの各値に対応するdouble値を取得してから合計しようとします。この形式では、どこにも助けが見つかりませんでした。ストリームを使用するとコードがクリーンアップされるのか、それとも面倒になるのかわかりません。
// safe assumptions - String/List (Key/Value) cannot be null or empty
// inputMap --> Map<String, List<String>>
Map<String, Double> finalResult = new HashMap<>();
for (Map.Entry<String, List<String>> entry : inputMap.entrySet()) {
Double score = 0.0;
for (String current: entry.getValue()) {
score += computeScore(current);
}
finalResult.put(entry.getKey(), score);
}
private Double computeScore(String a) { .. }
ストリームAPIとともにforEach
メソッドを使用して、探している結果を生成することもできます。
_Map<String, Double> resultSet = new HashMap<>();
inputMap.forEach((k, v) -> resultSet.put(k, v.stream()
.mapToDouble(s -> computeScore(s)).sum()));
_
s -> computeScore(s)
は、メソッド参照、つまり_T::computeScore
_を使用するように変更できます。ここで、T
はcomputeScore
を含むクラスの名前です。
_Map<String, Double> finalResult = inputMap.entrySet()
.stream()
.collect(Collectors.toMap(
Entry::getKey,
e -> e.getValue()
.stream()
.mapToDouble(str -> computeScore(str))
.sum()));
_
上記のコードはマップを反復処理し、同じキーで新しいマップを作成します。値を入力する前に、まず各値を反復処理します。これはリストであり、各リスト要素に対してcomputeScore()
値に入れるために収集されたスコア。
これはどう:
_Map<String, Double> finalResult = inputMap.entrySet()
.stream()
.map(entry -> new AbstractMap.SimpleEntry<String, Double>( // maps each key to a new
// Entry<String, Double>
entry.getKey(), // the same key
entry.getValue().stream()
.mapToDouble(string -> computeScore(string)).sum())) // List<String> mapped to
// List<Double> and summed
.collect(Collectors.toMap(Entry::getKey, Entry::getValue)); // collected by the same
// key and a newly
// calulcated value
_
上記のバージョンは、単一のcollect(..)
メソッドにマージできます。
_Map<String, Double> finalResult = inputMap.entrySet()
.stream()
.collect(Collectors.toMap(
Entry::getKey, // keeps the same key
entry -> entry.getValue()
.stream() // List<String> -> Stream<String>
// then Stream<String> -> Stream<Double>
.mapToDouble(string -> computeScore(string))
.sum())); // and summed
_
重要な部分:
collect(..)
は、 Collector
を使用して特定の戦略を使用して要素の削減を実行します。Entry::getKey
_は_entry -> entry.getKey
_のショートカットです。キーをマッピングするための関数。entry -> entry.getValue().stream()
は_Stream<String>
_を返しますmapToDouble(..)
は、DoubleStreamを返します。これには、要素を合計する集約操作 sum(..)
があり、一緒にマップの新しい値を作成します。ストリームベースのソリューションを使用するか、ループベースのソリューションを使用するかに関係なく、内部ループをメソッドに抽出するために有益であり、明確さと構造を追加します。
private double computeScore(Collection<String> strings)
{
return strings.stream().mapToDouble(this::computeScore).sum();
}
もちろん、これはループを使用して実装することもできますが、...それがまさにポイントです。このメソッドは、外側のループまたはマップエントリのストリームの値で呼び出すことができます。
外側のループまたはストリームもメソッドにプルできます。以下の例では、これを少し一般化しました。マップのキーのタイプは重要ではありません。値がList
またはCollection
インスタンスのどちらでもありません。
現在受け入れられている答えの代替として、ここでのストリームベースのソリューションは、手動で作成された新しいマップを埋めません。代わりに、Collector
を使用します。
(これは他の回答と似ていますが、抽出されたcomputeScore
メソッドは、ネストされたストリームに必要な、そうでなければかなりいラムダを大幅に簡素化すると思います)
import Java.util.Arrays;
import Java.util.Collection;
import Java.util.HashMap;
import Java.util.LinkedHashMap;
import Java.util.List;
import Java.util.Map;
import Java.util.Map.Entry;
import Java.util.stream.Collectors;
public class ToStreamOrNotToStream
{
public static void main(String[] args)
{
ToStreamOrNotToStream t = new ToStreamOrNotToStream();
Map<String, List<String>> inputMap =
new LinkedHashMap<String, List<String>>();
inputMap.put("A", Arrays.asList("1.0", "2.0", "3.0"));
inputMap.put("B", Arrays.asList("2.0", "3.0", "4.0"));
inputMap.put("C", Arrays.asList("3.0", "4.0", "5.0"));
System.out.println("Result A: " + t.computeA(inputMap));
System.out.println("Result B: " + t.computeB(inputMap));
}
private <T> Map<T, Double> computeA(
Map<T, ? extends Collection<String>> inputMap)
{
Map<T, Double> finalResult = new HashMap<>();
for (Entry<T, ? extends Collection<String>> entry : inputMap.entrySet())
{
double score = computeScore(entry.getValue());
finalResult.put(entry.getKey(), score);
}
return finalResult;
}
private <T> Map<T, Double> computeB(
Map<T, ? extends Collection<String>> inputMap)
{
return inputMap.entrySet().stream().collect(
Collectors.toMap(Entry::getKey, e -> computeScore(e.getValue())));
}
private double computeScore(Collection<String> strings)
{
return strings.stream().mapToDouble(this::computeScore).sum();
}
private double computeScore(String a)
{
return Double.parseDouble(a);
}
}
私はそれがやや短いことがわかりました:
value = startDates.entrySet().stream().mapToDouble(Entry::getValue).sum();