Java Streams | groupingBy相同的元素
我有一个单词流,我想根据相同元素(=单词)的出现对它们进行排序。
例如:{hello,world,hello}
至
Map<String, List>
你好你好你好}
世界,{世界}
到目前为止我有什么:
Map<Object, List> list = streamofWords.collect(Collectors.groupingBy(???));
问题1:流似乎丢失了他正在处理字符串的信息,因此编译器强制我将类型更改为Object,List
问题2:我不知道在胃肠道内放入什么,以同样的方式将其分组。 我知道我能够处理lambda表达式中的单个元素,但我不知道如何到达每个元素的“外部”以检查是否相等。
谢谢
您要搜索的KeyExtractor是标识function:
Map> list = streamofWords.collect(Collectors.groupingBy(Function.identity()));
编辑补充说明:
-
Function.identity()
使用一个方法返回一个’Function’,它只返回它获得的参数。 -
Collectors.groupingBy(Function
提供了一个收集器,它将流的所有元素收集到keyExtractor)Map
。 它使用keyExtractor实现来检查流的> S
类对象,并从中推导出类型为K
的键。 此键是映射的键,用于获取(或创建)添加了流元素的结果映射中的列表。
要获取Map
,您只需要告诉groupingBy
收集器您要按标识对值进行分组,因此函数x -> x
。
Map> occurrences = streamOfWords.collect(groupingBy(str -> str));
然而,这有点无用,因为你看到你有两次相同类型的信息。 您应该查看Map
,其中值表示Stream中String的出现。
Map occurrences = streamOfWords.collect(groupingBy(str -> str, counting()));
基本上不是使用groupingBy
返回值作为List
,而是使用下游收集器counting()
来告诉您要计算此值出现的次数。
你的排序要求应该意味着你应该有一个Map
(如果不同的字符串看起来相同的次数怎么办?),并且由于默认的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
的原因。
让我们再看一个例子。 现在流包含值“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将位于相同的“包”中。
查看源代码不会帮助您了解最初发生的情况。 如果您想了解它是如何在幕后实现的,那将非常有用。 但是首先尝试用更高级别的抽象来思考这个概念,然后事情会变得更加清晰。
希望能帮助到你! 🙂