我相信OP正在使用a将输入划分为等价类,并且所需的结果是等价类的成员列表,该成员是该类的最大值。Comparator
Comparator
不幸的是,使用值作为示例问题是一个可怕的例子。所有相等的值都是可互换的,因此不存在保留等效值的顺序的概念。也许一个更好的例子是使用字符串长度,其中所需的结果是从输入返回字符串列表,这些字符串在该输入中具有最长的长度。int
int
我不知道有什么方法可以在不将至少部分结果存储在集合中的情况下执行此操作。
给定一个输入集合,比如说
List<String> list = ... ;
...在两次传递中执行此操作非常简单,第一次用于获取最长长度,第二次用于筛选具有该长度的字符串:
int longest = list.stream()
.mapToInt(String::length)
.max()
.orElse(-1);
List<String> result = list.stream()
.filter(s -> s.length() == longest)
.collect(toList());
如果输入是不能多次遍历的流,则可以使用收集器仅计算单个传递的结果。编写这样的收集器并不困难,但有点乏味,因为有几个情况需要处理。在给定 的情况下,生成此类收集器的帮助器函数如下所示:Comparator
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;
}
});
}
这会将中间结果存储在 .不变量是任何此类列表中的所有元素在 .添加元素时,如果它小于列表中的元素,则忽略它;如果相等,则添加;如果它更大,则清空列表并添加新元素。合并也不是太难:返回具有较大元素的列表,但如果它们的元素相等,则会追加列表。ArrayList
Comparator
给定一个输入流,这非常易于使用:
Stream<String> input = ... ;
List<String> result = input.collect(maxList(comparing(String::length)));