yos*_*ico 16 java grouping java-8 java-stream collectors
如何通过每个条目限制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"));
Run Code Online (Sandbox Code Playgroud)
此方法返回简单组:
Map<String, List<StudentClass>> groupByTeachers = studentClasses
.stream().collect(
Collectors.groupingBy(StudentClass::getTeacher));
Run Code Online (Sandbox Code Playgroud)
如果我想限制返回的集合怎么办?让我们假设我只想要每个老师的前N个课程.怎么做到呢?
Tun*_*aki 17
可以引入一个新的收集器来限制结果列表中的元素数量.
此收集器将保留列表的头元素(按遭遇顺序).在收集期间达到限制时,累加器和组合器会丢弃每个元素.组合器代码有点棘手,但这样做的好处是不会添加额外的元素,只是为了以后丢弃.
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;
}
);
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
Map<String, List<StudentClass>> groupByTeachers =
studentClasses.stream()
.collect(groupingBy(
StudentClass::getTeacher,
limitingList(2)
));
Run Code Online (Sandbox Code Playgroud)
您可以使用collectionAndThen在结果列表上定义整理器操作。这样,您可以限制,过滤,排序,...列表:
int limit = 2;
Map<String, List<StudentClass>> groupByTeachers =
studentClasses.stream()
.collect(
groupingBy(
StudentClass::getTeacher,
collectingAndThen(
toList(),
l -> l.stream().limit(limit).collect(toList()))));
Run Code Online (Sandbox Code Playgroud)