如何按流中的某个最大值过滤流?
How can I filter stream by some max value from it?
假设我有一个对象流。
class MyObject {
private Some some; // Comparable
private Other value
}
单链中有做following things的成语吗?
- 给定
Stream<MyObject>
,
- 找到
some
的最大值。
- 地图
value
的 some
是最大值。
好像,
final List<MyObject> list = getList();
final Some max = list.stream().max(Comparator.naturalOrder())
final List<Other> list = list.stream()
.filter(e -> Objects.equals(e.some, max)
.map(e -> e.getValue()).collect(toList());
如果您必须一次性完成,您可以编写一个自定义收集器来将流减少为最大元素列表。这是基于 Stuart Marks 的实现。
List<MyObject> maxList = list.stream()
.collect(maxList(Comparator.comparing(MyObject::getSome)));
static <T> Collector<T,?,List<T>> maxList(Comparator<? super T> comp) {
return Collector.of(
ArrayList::new,
(list, t) -> {
int c;
if (list.isEmpty() || (c = comp.compare(t, list.get(0))) == 0) {
list.add(t);
} else if (c > 0) {
list.clear();
list.add(t);
}
},
(list1, list2) -> {
if (list1.isEmpty()) {
return list2;
}
if (list2.isEmpty()) {
return list1;
}
int r = comp.compare(list1.get(0), list2.get(0));
if (r < 0) {
return list2;
} else if (r > 0) {
return list1;
} else {
list1.addAll(list2);
return list1;
}
});
}
Collector 将维护一个 ArrayList 用于结果,并将每个元素累积到其中,检查该元素与当前列表的第一个元素的比较情况。 c = comp.compare(t, list.get(0))) == 0
部分将检查元素是否具有相同的最大值,如果是则将其添加到列表中。
如果您使用 Java 12+,您可以使用 Collectors.teeing
:
List<Other> maxObjects = list.stream().collect(
Collectors.teeing(
Collectors.maxBy(Comparator.comparing(MyObject::getSome)),
Collectors.groupingBy(
MyObject::getSome,
Collectors.mapping(
MyObject::getValue,
Collectors.toList())),
(max, groups) -> max.map(MyObject::getSome).map(groups::get).orElse(null)));
假设我有一个对象流。
class MyObject {
private Some some; // Comparable
private Other value
}
单链中有做following things的成语吗?
- 给定
Stream<MyObject>
, - 找到
some
的最大值。 - 地图
value
的some
是最大值。
好像,
final List<MyObject> list = getList();
final Some max = list.stream().max(Comparator.naturalOrder())
final List<Other> list = list.stream()
.filter(e -> Objects.equals(e.some, max)
.map(e -> e.getValue()).collect(toList());
如果您必须一次性完成,您可以编写一个自定义收集器来将流减少为最大元素列表。这是基于 Stuart Marks
List<MyObject> maxList = list.stream()
.collect(maxList(Comparator.comparing(MyObject::getSome)));
static <T> Collector<T,?,List<T>> maxList(Comparator<? super T> comp) {
return Collector.of(
ArrayList::new,
(list, t) -> {
int c;
if (list.isEmpty() || (c = comp.compare(t, list.get(0))) == 0) {
list.add(t);
} else if (c > 0) {
list.clear();
list.add(t);
}
},
(list1, list2) -> {
if (list1.isEmpty()) {
return list2;
}
if (list2.isEmpty()) {
return list1;
}
int r = comp.compare(list1.get(0), list2.get(0));
if (r < 0) {
return list2;
} else if (r > 0) {
return list1;
} else {
list1.addAll(list2);
return list1;
}
});
}
Collector 将维护一个 ArrayList 用于结果,并将每个元素累积到其中,检查该元素与当前列表的第一个元素的比较情况。 c = comp.compare(t, list.get(0))) == 0
部分将检查元素是否具有相同的最大值,如果是则将其添加到列表中。
如果您使用 Java 12+,您可以使用 Collectors.teeing
:
List<Other> maxObjects = list.stream().collect(
Collectors.teeing(
Collectors.maxBy(Comparator.comparing(MyObject::getSome)),
Collectors.groupingBy(
MyObject::getSome,
Collectors.mapping(
MyObject::getValue,
Collectors.toList())),
(max, groups) -> max.map(MyObject::getSome).map(groups::get).orElse(null)));