[英]Java Streams | groupingBy same elements
我有一個單詞流,我想根據相同元素(=單詞)的出現對它們進行排序。
例如:{hello,world,hello}
至
Map<String, List<String>>
你好你好你好}
世界,{世界}
到目前為止我有什么:
Map<Object, List<String>> list = streamofWords.collect(Collectors.groupingBy(???));
問題1:流似乎丟失了他正在處理字符串的信息,因此編譯器強制我將類型更改為Object,List
問題2:我不知道在胃腸道內放入什么,以同樣的方式將其分組。 我知道我能夠處理lambda表達式中的單個元素,但我不知道如何到達每個元素的“外部”以檢查是否相等。
謝謝
要獲取Map<String, List<String>>
,您只需要告訴groupingBy
收集器您要按標識對值進行分組,因此函數x -> x
。
Map<String, List<String>> occurrences =
streamOfWords.collect(groupingBy(str -> str));
然而,這有點無用,因為你看到你有兩次相同類型的信息。 您應該查看Map<String, Long>
,其中值表示Stream中String的出現。
Map<String, Long> occurrences =
streamOfWords.collect(groupingBy(str -> str, counting()));
基本上不是使用groupingBy
返回值作為List
,而是使用下游收集器counting()
來告訴您要計算此值出現的次數。
你的排序要求應該意味着你應該有一個Map<Long, List<String>>
(如果不同的字符串出現的次數是多少?),並且由於默認的toMap
collector返回一個HashMap
,它沒有排序的概念,但您可以將元素存儲在TreeMap
。
我試着總結一下我在評論中所說的內容。
你似乎對str -> str
如何判斷“你好”或“世界”是否有所不同感到麻煩。
首先str -> str
是一個函數,也就是說,對於輸入x,產生一個值f(x)。 例如, f(x) = x + 2
是對於任何值x
返回x + 2
的函數。
這里我們使用identity函數,即f(x) = x
。 當您從Map
收集管道中的元素時,將在調用此函數之前從該值獲取鍵。 所以在你的例子中,你有3個身份函數產生的元素:
f("hello") = "hello"
f("world") = "world"
到現在為止還挺好。
現在,當調用collect()
時,對於流中的每個值,您將在其上應用函數並計算結果(這將是Map
的鍵)。 如果一個鍵已經存在,我們將獲取當前映射的值,並在List
合並我們想要放置的值(即剛剛應用該函數的值)與此先前的映射值。 這就是你最后得到Map<String, List<String>>
的原因。
讓我們再看一個例子。 現在流包含值“hello”,“world”和“hey”,我們想要應用於組合元素的函數是str -> str.substring(0, 2)
,即取得的函數字符串的前兩個字符。
同樣,我們有:
f("hello") = "he"
f("world") = "wo"
f("hey") = "he"
在這里,您會看到“hello”和“hey”在應用函數時產生相同的鍵,因此在收集它們時它們將被分組在同一個List
,因此最終結果為:
"he" -> ["hello", "hey"]
"wo" -> ["world"]
要與數學進行類比,你可以采用任何非雙射函數,例如x 2 。 對於x = -2
和x = 2
我們得到f(x) = 4
。 因此,如果我們通過此函數對整數進行分組,則-2和2將位於相同的“包”中。
查看源代碼不會幫助您了解最初發生的情況。 如果你想知道它是如何在幕后實現的話,它會很有用。 但是首先嘗試用更高級別的抽象來思考這個概念,然后事情會變得更加清晰。
希望能幫助到你! :)
您要搜索的KeyExtractor是標識功能:
Map<String, List<String>> list = streamofWords.collect(Collectors.groupingBy(Function.identity()));
編輯補充說明:
Function.identity()
使用一個方法返回一個'Function',它只返回它獲得的參數。 Collectors.groupingBy(Function<S, K> keyExtractor)
提供了一個收集器,它將流的所有元素收集到Map<K, List<S>>
。 它使用keyExtractor實現來檢查流的S
類對象,並從中推導出類型為K
的鍵。 此鍵是映射的鍵,用於獲取(或創建)添加了流元素的結果映射中的列表。 如果你想按對象的某些字段進行分組,而不是整個對象,並且你不想改變你的equals和hashCode方法,我會創建一個包含一組鍵的類,用於分組:
import java.util.Arrays;
@Getter
public class MultiKey {
public MultiKey(Object... keys) {
this.keys = keys;
}
private Object[] keys;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MultiKey multiKey = (MultiKey) o;
return Arrays.equals(keys, multiKey.keys);
}
@Override
public int hashCode() {
return Arrays.hashCode(keys);
}
}
groupingBy
本身:
Map<MultiKey, List<VhfEventView>> groupedList = list
.stream()
.collect(Collectors.groupingBy(
e -> new MultiKey(e.getGroupingKey1(), e.getGroupingKey2())));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.