2015-04-29 56 views
6

我有一個單詞流,我想根據相同元素(=單詞)的出現對它們進行排序。Java Streams |分組通過相同的元素

例如:{你好,世界,你好}

Map<String, List<String>> 

您好:{你好,你好}

世界,{世界}

我有什麼事這麼遠:

Map<Object, List<String>> list = streamofWords.collect(Collectors.groupingBy(???)); 

P問題2:我不知道把什麼東西放在parentesis中去分組它,但是我不知道怎麼把它們放在一個對象中,所以編譯器會強制我把它改爲Object,List

問題2:相同的情況。我知道我能夠處理lambda表達式中的單個元素,但我不知道如何到達每個元素的「外部」以檢查是否相等。

謝謝

回答

5

您正在搜索的KeyExtractor是身份的功能:

Map<String, List<String>> list = streamofWords.collect(Collectors.groupingBy(Function.identity())); 

編輯補充解釋:

  • Function.identity() retuns一個 '功能' 與不執行任何一個方法不僅僅是返回它得到的參數。
  • Collectors.groupingBy(Function<S, K> keyExtractor)提供了一個收集器,它將流的所有元素收集到一個Map<K, List<S>>。它使用keyExtractor實現來檢查類型爲S的流的對象,並從中推導出類型爲K的密鑰。此鍵是用於在流元素添加到的結果映射中獲取(或創建)列表的映射關鍵字。
+0

謝謝,一旦我確認,我會盡快給你接受的答案。 P.S .:你介意解釋這是如何工作的嗎?特別是當我使用流時,我想要在列表中獲取元素的元數據時,策略是什麼?不知何故,我似乎沒有得到它。我認爲這可能對未來的讀者有所幫助。 – SklogW

+2

@SklogW新增說明。現在更清楚了嗎? – flo

+0

是的,有一點點,只是一個小東西:是「s - > s」,因爲lambda表達式真的足以暗示我想要具有相同標識的元素。我不知道如何告訴功能,我想要相同的元素。 s - > s.equals(s)將是無稽之談,對吧? – SklogW

7

要得到Map<String, List<String>>,你只需要告訴您要GROUP BY身份值groupingBy收藏家,所以功能x -> x

Map<String, List<String>> occurrences = 
    streamOfWords.collect(groupingBy(str -> str)); 

然而,這有點無用,正如你看到你有兩次相同類型的信息。您應該查看一個Map<String, Long>,其中的值指示Stream中字符串的出現次數。

Map<String, Long> occurrences = 
    streamOfWords.collect(groupingBy(str -> str, counting())); 

基本上而不是一個groupingBy返回值List的,你用下游收集counting()告訴你要計算的時間出現此值的數量。

你的那種要求應該意味着,你應該有一個Map<Long, List<String>>(如果不同的字符串出現相同的次數?),並作爲默認toMap收集返回HashMap,它有沒有順序的概念,但你可以存儲取而代之的是TreeMap中的元素。


我試着總結一下我在評論中所說的內容。

你似乎有問題如何str -> str可以告訴「你好」或「世界」是不同的。

首先str -> str是一個函數,也就是說,對於輸入x產生一個值f(x)。例如,f(x) = x + 2是一個函數,對於任何值x都返回x + 2

這裏我們使用的是標識功能,即f(x) = x。當您從Map的管道中收集元素時,將在此之前調用此函數以從值中獲取密鑰。因此,在你的榜樣,你有3個要素,其身份功能得到:

f("hello") = "hello" 
f("world") = "world" 

到目前爲止好。

現在,當調用collect()時,對於流中的每個值,您將對其應用該函數並評估結果(這將是Map中的關鍵字)。如果一個密鑰已經存在,我們取當前映射的值,然後我們將我們想要放入的值(即剛剛應用該函數的值)合併到該先前映射的值中。這就是爲什麼你最後得到Map<String, List<String>>

再舉一個例子。現在,該流包含值「hello」,「world」和「hey」,我們想要將這些元素分組的函數是str -> str.substring(0, 2),即採用String的前兩個字符的函數。

同樣,我們有:

f("hello") = "he" 
f("world") = "wo" 
f("hey") = "he" 

這裏你可以看到,這兩個「你好」和「嘿」應用功能,因此他們將在同一List收集時,它們被組合時產生相同的密鑰,從而使最終的結果是:

"he" -> ["hello", "hey"] 
"wo" -> ["world"] 

要與數學打個比方,你可能會採取任何非雙射函數,如X 。對於x = -2x = 2我們有f(x) = 4。所以如果我們用這個函數對整數進行分組,-2和2將會在同一個「包」中。

查看源代碼不會幫助您瞭解最初發生的情況。如果你想知道如何在引擎蓋下實現,這很有用。但首先要考慮更高抽象層次的概念,然後事情會變得更加清晰。

希望它有幫助! :)

+0

你是否介意在使用流時,如何在列表中收集元素的元數據?我明白,每個元素都是相互處理的,但它們是如何工作的?使用流時的抽象級別讓我感到困惑。 – SklogW

+2

@SklogW你遇到哪些具體問題?源代碼不是很容易理解。對於高層次的圖片,「groupingBy」是一個收集器,它在遍歷管道時累積「Map 」中的元素。請記住,'str - > str'是一個函數,所以基本上不用'map.put(str,someValue)''你會做'map.put(function.apply(str),someValue)'。如果您有兩個相同的鍵,則將列表中的值合併,等等。類型信息被保留,因爲'Function'是一個通用接口,所以你知道應用它後會得到哪種類型。 –

+0

在我們的例子中,'function.apply(str)'將返回'str',因爲它是標識函數,所以基本上每個相同的字符串(根據equals)將被合併到一個包含所有這些字符串的列表中與該鍵相關聯的值。這就是爲什麼你最後有一個'Map >'。 –

相關問題