博客 / 詳情

返回

簡單聊聊:Stream.reduce()用法解析

基本使用
先舉一個簡單的例子:

算法題:Words
題目描述
每個句子由多個單詞組成,句子中的每個單詞的長度都可能不一樣,我們假設每個單詞的長度Ni為該單詞的重量,你需要做的就是給出整個句子的平均重量V。

解答要求
時間限制:1000ms, 內存限制:100MB
輸入
輸入只有一行,包含一個字符串S(長度不會超過100),代表整個句子,句子中只包含大小寫的英文字母,每個單詞之間有一個空格。

輸出
輸出句子S的平均重量V(四捨五入保留兩位小數)。

Who Love Solo
輸出樣例
3.67

這道題的意思是求一句話中每個單詞的平均長度,我們求得總長度然後除以單詞數量即可,剛好能用到reduce()這個方法。

public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] s = sc.nextLine().split(" ");
double res = Arrays.stream(s).mapToDouble(a ->a.length()).reduce(0,(a,b)->a+b);
System.out.println(String.format("%.2f",res/s.length));
}
}

在代碼中,.reduce(0,(a,b)->a+b);這一塊就是我們經典的使用案例,我們要先明白其中a,b的含義,然後再學習如何使用
關鍵概念:初始值的定義(Identity),累加器(Accumulator),組合器(Combiner)

Identity : 定義一個元素代表是歸併操作的初始值,如果Stream 是空的,也是Stream 的默認結果
Accumulator: 定義一個帶兩個參數的函數,第一個參數是上個歸併函數的返回值,第二個是Strem 中下一個元素。
Combiner: 調用一個函數來組合歸併操作的結果,當歸並是並行執行或者當累加器的函數和累加器的實現類型不匹配時才會調用此函數。
也就是説0就是我們的初始值,(a,b)->a+b就是我們的累加器,其中a就是上一次的計算結果,b就是Stream流中當前元素,而後面的a+b則是計算規則,比如如果我們改成a*b,那就是計算乘積了,當然我們也可以用方法引用來代替 lambda 表達式。

double res = Arrays.stream(s).mapToDouble(a ->a.length()).reduce(0,Double::sum);
1
這就是最基本的使用了,不知道小夥伴們有沒有學會呢?

額外舉例

當然,我們可以用reduce 方法處理其他類型的 stream,例如,可以操作一個 String 類型的數組,把數組的字符串進行拼接。

List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters
.stream()
.reduce("", (partialString, element) -> partialString + element);
assertThat(result).isEqualTo("abcde");

同樣也可以用方法引用來簡化代碼

String result = letters.stream().reduce("", String::concat);
assertThat(result).isEqualTo("abcde");

我們再把上面的拼接字符串的例子改下需求,先把字符串轉變成大寫然後再拼接

String result = letters
.stream()
.reduce(
"", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase());
assertThat(result).isEqualTo("ABCDE");

另外,我們可以並行地歸併元素(並行歸併),如下並行歸併一個數字數組來求和

List<Integer> ages = Arrays.asList(25, 30, 45, 28, 32);
int computedAges = ages.parallelStream().reduce(0, a, b -> a + b, Integer::sum);

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.