流在分组后不保留顺序

2022-09-03 16:53:55

我有一个列表名称可用座位我正在按blockIndex属性进行排序和分组,如下所示:

availableSeats.stream()
                .sorted(Comparator.comparing(SeatedTicketAssignment::getBlockIndex))
                .collect(Collectors.groupingBy(SeatedTicketAssignment::getBlockIndex))
                .forEach((block, blockAssignments) -> {
                     //Rest of the code
                } 

问题是分组依据的结果不是按块索引排序的。


答案 1

请记住,将返回一个,这并不能保证订单。如果希望排序的顺序与聚合标识(结果)的显示顺序相同,则可以使用 :Collectors#groupingBy(Function)HashMapi % 2 == 0LinkedHashMap

.collect(Collectors.groupingBy(i -> i % 2 == 0, LinkedHashMap::new, Collectors.toList()))

将返回 a(因为您的收集器按布尔值分组)。此外,由于收集器使用的列表是 一个 ,因此它应该保留流相对于列表的迭代顺序。LinkedHashMap<Boolean, List<SeatedTicketAssignment>>ArrayList


答案 2

不幸的是,Stream API实现并不知道这样一个事实,即您传递的流已经按您需要的内容进行排序,因此“分组”实际上是微不足道的。因此,它使用默认方式,该方式本质上与此SO答案相似,即为组创建一个Map并用流的元素填充它。默认情况下,使用的Map实现是HashMap(请参阅此处的代码),出于性能原因,这很好,但对您的目标不利,因为HashMap不会保留键的顺序,而不是第一次排序。

在 Stream API 中仅作为“收集器”实现“分组依据”似乎有点不走运,因此您无法先分组,然后在单行中排序。但这似乎是有意为之的:没有办法在没有完全实现结果的情况下实现Group By,因此它不能懒惰,因此必须是一个收集器。@Rogue LinkedHashMap提供了一个很好的技巧,但对我来说,它绑定到实现细节。我仍然会再写几行代码和第一组,然后按键对列表的条目进行排序(即实际分组的HashMap)。最有可能的是,它会更快。


推荐