[英]Stream doesn't preserve the order after grouping
我有一個List名稱availableSeats我正在通過blockIndex屬性進行排序和分組,如下所示:
availableSeats.stream()
.sorted(Comparator.comparing(SeatedTicketAssignment::getBlockIndex))
.collect(Collectors.groupingBy(SeatedTicketAssignment::getBlockIndex))
.forEach((block, blockAssignments) -> {
//Rest of the code
}
問題是分組的結果不是由blockIndex排序的。
請記住, Collectors#groupingBy(Function)
將返回一個HashMap
,它不保證順序。 如果您希望排序符合聚合標識(您的i % 2 == 0
結果)顯示的順序,那么您可以使用LinkedHashMap
:
.collect(Collectors.groupingBy(i -> i % 2 == 0, LinkedHashMap::new, Collectors.toList()))
將返回LinkedHashMap<Boolean, List<SeatedTicketAssignment>>
(因為您的收集器按布爾值分組)。 此外,由於收集器使用的列表是ArrayList
,因此它應該保留流相對於列表的迭代順序。
不幸的是,Stream API實現並不知道您傳遞的流已按您所需的順序排序,因此“分組”實際上是微不足道的。 因此,它使用默認方式,它基本上類似於這個SO答案,即為組創建一個Map並用流的元素填充它。 默認情況下,使用的Map實現是HashMap(請參閱此處的代碼 ),這有助於提高性能但對目標不利,因為HashMap不會保留鍵的順序而不是第一次排序。
可能看起來有些不吉利的是Group By僅在Stream API中作為“收集器”實現,因此您不能先進行分組,然后進行單行排序。 但這似乎是有意的:沒有完全實現結果就沒有辦法實現Group By,所以它不能是懶惰的,因此必須是一個收集器。 @Rogue為LinkedHashMap提供了一個很好的技巧,但對我來說它是綁定到實現細節。 我仍然會寫幾行代碼和第一組,然后按鍵對列表的條目(即實際分組的HashMap)進行排序。 最有可能的是它會更快。
由於groupingBy
收集器不需要排序輸入,因此您可以在收集后對組進行排序。 這將比首先對項目排序更快,無論如何,假設組中的項目少於項目:
availableSeats.stream()
.collect(Collectors.groupingBy(SeatedTicketAssignment::getBlockIndex))
.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getKey))
.forEach(mapEntry -> {
//Rest of the code
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.