Javaだとうまくいかない?
例えば、文字列の長さの合計を計算したい場合、Pythonだとこうします。
>>> fruits = [ 'apple', 'orange', 'kiwi' ]
>>> reduce(lambda sum, elm: sum + len(elm), fruits, 0)
15
map で要素のサイズに変換して reduce だろという意見はおいておいて下さい (笑
Javaだとこう...かと思いきや、エラーになります。 (´・ω・`)
List<String> fruits = Arrays.asList("apple", "orange", "kiwi");
fruits.stream()
.reduce(0, (sum, elm) -> sum + elm.length()); // Integer: 15 ?
-------------------------------------------------------------
COMPILATION ERROR :
-------------------------------------------------------------
Javatest.java:[33,8] error: no suitable method found for reduce(int,(sum,elm)-[...]gth())
1 error
-------------------------------------------------------------
引数2個の reduce() は、要素の型と同じ型の戻り値をかえす
普段使っている? list.stream().reduce(...)
は引数2個 (初期値 と lambda) のやつです。
T reduce(T identity,
BinaryOperator<T> accumulator);
要素の型と戻り値の型が同じ T
なので、型を合わせないとコンパイルが通りません。
List<String> fruits = Arrays.asList("apple", "orange", "kiwi");
String result = fruits.stream()
.reduce("I like ", (sum, elm) -> sum + ", " + elm)); // String: "I like apple, orange, kiwi, "
引数3個の reduce() は、要素の型と異なる型の戻り値をかえせる
実は引数3個の list.stream().reduce(...)
があります。これを使うと要素の型 T
と異なる型 U
の値を返す事ができます。
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
例えば以下の様に書けます。sum
=int, elm
=String, sum1
=int, sum2
=int です。
List<String> fruits = Arrays.asList("apple", "orange", "kiwi");
int result = fruits.stream().reduce(
0, // 初期値
(sum, elm) -> sum + elm.length(), // accumulator. 中間生成物を作る.
(sum1, sum2) -> sum1 + sum2); // combiner. 中間生成物どうしをマージする.
accumulator (第2引数) と combiner (第3引数) を指定しています。何故2つもLambdaが必要かと言うと、並列実行 .parallel()
される場合に必要になります。
例えば、accumulator (sum, elm) -> sum + elm.length()
が並列で実行されると中間生成物 (int型) が複数できる事になります。
このint型の中間生成物同士をマージする為に combiner (sum1, sum2) -> sum1 + sum2
が必要になります。
例
例えば、2-threadで並列実行された場合、以下の様になるだろうと考えられます。
実際の処理の流れとは少々異なりますが、簡単化して書いています
まず、全ての要素 "apple", "orange", "kiwi"
を accumulator (第2引数) で処理し、中間生成物を作ります。
- 初期値 + 要素1 ==> 中間生成物1
(0, "apple") -> 5
- 初期値 + 要素2 ==> 中間生成物2
(0, "orange") -> 6
- 中間生成物1 + 要素3 ==> 中間生成物3
(5, "kiwi") -> 9
生成された中間生成物を全て combiner (第3引数) でマージし、一つの値に集約します。
- 中間生成物2 + 中間生成物3 ==> 中間生成物4
(6, 9) -> 15
最後に残った 中間生成物4=15
が最終的な戻り値となります。