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 = -2x = 2我们得到f(x) = 4 。 因此,如果我们通过此函数对整数进行分组,则-2和2将位于相同的“包”中。

查看源代码不会帮助您了解最初发生的情况。 如果您想了解它是如何在幕后实现的,那将非常有用。 但是首先尝试用更高级别的抽象来思考这个概念,然后事情会变得更加清晰。

希望能帮助到你! 🙂