[英]Limit groupBy in Java 8
如何通過每個條目限制groupBy?
例如(基於此示例: stream groupBy ):
studentClasses.add(new StudentClass("Kumar", 101, "Intro to Web"));
studentClasses.add(new StudentClass("White", 102, "Advanced Java"));
studentClasses.add(new StudentClass("Kumar", 101, "Intro to Cobol"));
studentClasses.add(new StudentClass("White", 101, "Intro to Web"));
studentClasses.add(new StudentClass("White", 102, "Advanced Web"));
studentClasses.add(new StudentClass("Sargent", 106, "Advanced Web"));
studentClasses.add(new StudentClass("Sargent", 103, "Advanced Web"));
studentClasses.add(new StudentClass("Sargent", 104, "Advanced Web"));
studentClasses.add(new StudentClass("Sargent", 105, "Advanced Web"));
此方法返回簡單組:
Map<String, List<StudentClass>> groupByTeachers = studentClasses
.stream().collect(
Collectors.groupingBy(StudentClass::getTeacher));
如果我想限制返回的集合怎么辦? 讓我們假設我只想要每個老師的前N個課程。 怎么做到呢?
可以引入一個新的收集器來限制結果列表中的元素數量。
此收集器將保留列表的頭元素( 按遭遇順序 )。 在收集期間達到限制時,累加器和組合器會丟棄每個元素。 組合器代碼有點棘手,但這樣做的好處是不會添加額外的元素,只是為了以后丟棄。
private static <T> Collector<T, ?, List<T>> limitingList(int limit) {
return Collector.of(
ArrayList::new,
(l, e) -> { if (l.size() < limit) l.add(e); },
(l1, l2) -> {
l1.addAll(l2.subList(0, Math.min(l2.size(), Math.max(0, limit - l1.size()))));
return l1;
}
);
}
然后像這樣使用它:
Map<String, List<StudentClass>> groupByTeachers =
studentClasses.stream()
.collect(groupingBy(
StudentClass::getTeacher,
limitingList(2)
));
你可以使用collectingAndThen所得到的名單上定義的整理操作。 這樣你可以限制,過濾,排序......列表:
int limit = 2;
Map<String, List<StudentClass>> groupByTeachers =
studentClasses.stream()
.collect(
groupingBy(
StudentClass::getTeacher,
collectingAndThen(
toList(),
l -> l.stream().limit(limit).collect(toList()))));
為此,您需要.stream()
Map的結果。 你可以這樣做:
// Part that comes from your example
Map<String, List<StudentClass>> groupByTeachers = studentClasses
.stream().collect(
Collectors.groupingBy(StudentClass::getTeacher));
// Create a new stream and limit the result
groupByTeachers =
groupByTeachers.entrySet().stream()
.limit(N) // The actual limit
.collect(Collectors.toMap(
e -> e.getKey(),
e -> e.getValue()
));
這不是一種非常理想的方法。 但是如果你在初始列表中使用.limit()
,則分組結果將是不正確的。 這是保證限制的最安全的方法。
編輯:
正如評論中所述,這限制了教師,而不是每位教師的課程。 在這種情況下,你可以這樣做:
groupByTeachers =
groupByTeachers.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey(),
e -> e.getValue().stream().limit(N).collect(Collectors.toList()) // Limit the classes PER teacher
));
這將為您提供所需的結果,但它仍然會對流的所有元素進行分類:
final int N = 10;
final HashMap<String, List<StudentClass>> groupByTeachers =
studentClasses.stream().collect(
groupingBy(StudentClass::getTeacher, HashMap::new,
collectingAndThen(toList(), list -> list.subList(0, Math.min(list.size(), N)))));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.