[英]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.