我有一个列表名称 availableSeats 我正在按 blockIndex 属性进行排序和分组,如下所示:
availableSeats.stream()
.sorted(Comparator.comparing(SeatedTicketAssignment::getBlockIndex))
.collect(Collectors.groupingBy(SeatedTicketAssignment::getBlockIndex))
.forEach((block, blockAssignments) -> {
//Rest of the code
}
问题是分组的结果没有按blockIndex排序。
答案 0 :(得分:8)
请注意,Collectors#groupingBy(Function)
将返回HashMap
,但不保证订单。如果您希望订购符合聚合身份(您的i % 2 == 0
结果)显示的顺序,那么您可以使用LinkedHashMap
:
.collect(Collectors.groupingBy(i -> i % 2 == 0, LinkedHashMap::new, Collectors.toList()))
将返回LinkedHashMap<Boolean, List<SeatedTicketAssignment>>
(因为您的收集器按布尔值分组)。此外,由于收集器使用的列表是ArrayList
,因此它应该保留流相对于列表的迭代顺序。
答案 1 :(得分:1)
不幸的是,Stream API实现并没有意识到这样一个事实,即您传递的流已按您所需的顺序排序,因此&#34;分组&#34;实际上是微不足道的。因此,它使用与此SO answer基本类似的默认方式,即为组创建Map并使用流的元素填充它。默认情况下,使用的Map实现是HashMap(请参阅code here),这有助于提高性能,但不利于您的目标,因为HashMap不会保留键的顺序,而不是第一次排序。
Group By在Stream API中实现仅作为&#34;收集器&#34;似乎有点不吉利。因此,您不能先进行分组,然后进行单行分类。但这似乎是故意的:如果没有完全实现结果,就没有办法实现Group By,因此它不会是懒惰的,因此必须是收集器。 @Rogue为LinkedHashMap提供了一个很好的技巧,但对我来说它是绑定到实现细节。我仍然会写几行代码和第一组,然后按键对列表的条目(即实际分组的HashMap)进行排序。最有可能的是它会更快。
答案 2 :(得分:1)
由于groupingBy
收集器不需要排序输入,因此您可以在收集后对组进行排序。这将比首先对项目排序更快,无论如何,假设组中的项目少于项目:
availableSeats.stream()
.collect(Collectors.groupingBy(SeatedTicketAssignment::getBlockIndex))
.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getKey))
.forEach(mapEntry -> {
//Rest of the code
}