java - 如何强制 max 返回 Java Stream 中的所有最大值?

标签 java collections lambda java-8 java-stream

我已经在 J​​ava 8 lambdas 和流上测试了一点 max 函数,似乎在执行 max 的情况下,即使有多个对象进行比较为 0,它返回绑定(bind)候选中的任意元素,无需进一步考虑。

对于这种最大预期行为是否有明显的技巧或功能,以便返回所有最大值?我在 API 中看不到任何内容,但我确信它一定存在比手动比较更好的东西。

例如:

// myComparator is an IntegerComparator
Stream.of(1, 3, 5, 3, 2, 3, 5)
    .max(myComparator)
    .forEach(System.out::println);
// Would print 5, 5 in any order.

最佳答案

我相信 OP 正在使用 Comparator 将输入划分为等价类,并且所需的结果是根据该 Comparator 最大的等价类成员列表.

不幸的是,使用 int 值作为示例问题是一个糟糕的例子。所有相等的 int 值都是可替代的,因此没有保留等值(value)顺序的概念。也许一个更好的例子是使用字符串长度,其中期望的结果是从输入中返回一个字符串列表,这些字符串在该输入中都具有最长的长度。

如果不将至少部分结果存储在集合中,我不知道有任何方法可以做到这一点。

给定一个输入集合,比如说

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());

如果输入是流,cannot be traversed more than once ,可以使用收集器仅在单遍中计算结果。编写这样的收集器并不难,但有点繁琐,因为要处理几种情况。给定一个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)));

关于java - 如何强制 max 返回 Java Stream 中的所有最大值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29334404/

相关文章:

java - HashMap : can get value if key is hardcoded string but not if it is a variable

.net - 类似于 IDictionary<TKey, TValue>,但仅适用于 .NET 中的键(不需要值)?

java - 在 lambda foreach 表达式 java 8 中获取索引

ruby - proc 数组或 lambda 数组

java - 级联删除不适用于 Ektorp(couchdb 的 Java 持久性 API)

java - REST POST Api 是否会像 Get Api 一样由浏览器自动重试?

c# - 键是一对整数的字典

java - Java中是否有Map支持通过(非唯一)值查找键?

java - 从嵌套的 RecyclerView 中删除项目

c# - x => x + 1和x => x + = 1之间有区别吗?