簡體   English   中英

從lambda表達式中排序和子列表

[英]Sorting and sub listing from lambda expression

我有一個包含以下元素的數組列表:

List<Record> list = new ArrayList<>();
list.add(new Record(3, "32"));
list.add(new Record(4, "42"));
list.add(new Record(1, "12"));
list.add(new Record(1, "11"));
list.add(new Record(2, "22"));
list.add(new Record(5, "52"));
list.add(new Record(5, "53"));
list.add(new Record(5, "51"));

Record是一個簡單的POJO,它有id和name

我想在列表中做那些。

  • 創建一個像Map<Integer, List<Record>>這樣的Map<Integer, List<Record>>其中一個密鑰是id,而更簡潔的密鑰添加為列表。我已經完成了下面的操作。

     Map<Integer, List<Record>> map = list.stream() .collect(Collectors.groupingBy(Record::getId, HashMap::new, Collectors.toList())); 
  • 現在我想按名稱和子列表對列表進行排序,以提供內部限制

     map.forEach((k, v) -> v.stream().sorted(Comparator.comparing(Record::getName))); map.forEach((k, v) -> map.put(k, v.subList(0, Math.min(**limit**, v.size())))); 

我已經嘗試過,看起來這不是一個好方法。 有誰能建議更好的方法?

您可以使用Java 8 Collectors.collectingAndThen()方法:

Map<Integer, List<Record>> map = list.stream()
    .collect(Collectors.groupingBy(
        Record::getId,
        Collectors.collectingAndThen(
            Collectors.toList(),
            records -> records.stream()
                              .sorted(Comparator.comparing(Record::getName))
                              .limit(limit)
                              .collect(Collectors.toList()))));

你可以使用Collectors.collectingAndThen

Map<Integer, List<Record>> result = list.stream()
    .collect(Collectors.groupingBy(
         Record::getId,
         Collectors.collectingAndThen(
             Collectors.toCollection(ArrayList::new),
             v -> {
                 v.sort(Comparator.comparing(Record::getName));
                 return v.subList(0, Math.min(LIMIT, v.size()));
             })));

此解決方案避免為每個列表組創建新流。

正如在這個答案中所指出的,通過使用Collectors.toCollection(ArrayList::new)我們確保列表是可變的,以便我們以后可以對其進行排序。

您可以使用

Map<Integer, List<Record>> map = list.stream()
    .collect(Collectors.groupingBy(Record::getId,Collectors.toCollection(ArrayList::new)));
map.values().forEach(l -> {
    list.sort(Comparator.comparing(Record::getName));
    l.subList(limit, l.size()).clear();
});

使用Collectors.toCollection(ArrayList::new)我們確保結果列表是可變的。 然后我們就地對列表進行排序並刪除不必要的值。 我們不是構建包含我們想要的元素的子列表(它將保留對完整列表的引用),而是構建我們不想要的元素的子列表並clear()它,以有效地從原始列表中刪除這些元素。

您也可以將其寫為單個語句:

    Map<Integer, List<Record>> map = list.stream()
        .collect(Collectors.groupingBy(Record::getId,
            Collectors.collectingAndThen(
                Collectors.toCollection(ArrayList::new),
                l -> {
                    list.sort(Comparator.comparing(Record::getName));
                    l.subList(limit, l.size()).clear();
                    l.trimToSize();
                    return l;
                })));

作為獎勵,我還添加了l.trimToSize(); 如果前面的.subList(limit, l.size()).clear()刪除了很多元素,則指示ArrayList使用較小的數組。 由於這可能意味着復制操作,因此這是CPU時間和內存之間的權衡。 因此,如果結果僅在之后的相當短的時間內使用,則不會使用trimToSize()


使用StreamEx時,操作變得更簡單(並且可能更有效):

Map<Integer, List<Record>> map = list.stream()
    .collect(Collectors.groupingBy(Record::getId,
             MoreCollectors.least(Comparator.comparing(Record::getName), limit)));
list.stream()
    .collect(Collectors.groupingBy(
          Record::getId,
          Collectors.collectingAndThen(
                   Collectors.toList(),
                   x -> x.stream()
                         .sorted(Comparator.comparing(Record::getName))
                         .limit(limit)
                         .collect(Collectors.toList())))); 

您可以收集地圖中的項目之前進行排序。 對於限制位,你可以使用collectingAndThen到后處理的列表和stream.limit它。

Map<Integer, List<Record>> map = list.stream()
        .sorted(Comparator.comparing(Record::getName))
        .collect(Collectors.groupingBy(Record::getId, 
                Collectors.collectingAndThen(Collectors.toList(), 
                        l -> l.stream().limit(limit).collect(Collectors.toList()))));

如果limit = 2 ,則會產生

{1=[Record(id=1, name=11), Record(id=1, name=12)], 
 2=[Record(id=2, name=22)], 
 3=[Record(id=3, name=32)], 
 4=[Record(id=4, name=42)], 
 5=[Record(id=5, name=51), Record(id=5, name=52)]}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM