使用Java 8流方法获取最后的最大值

Dru*_*les 16 java java-8 java-stream

给定一个具有属性的项目列表,我试图让最后一个项目显示所述属性的最大值.

例如,对于以下对象列表:

t  i
A: 3
D: 7 *
F: 4
C: 5
X: 7 *
M: 6
Run Code Online (Sandbox Code Playgroud)

我可以得到最高的东西之一i:

Thing t = items.stream()
        .max(Comparator.comparingLong(Thing::getI))
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

但是,这会得到我Thing t = D.是否有一种干净而优雅的方式来获取最后一项,即X在这种情况下?

一种可能的解决方案是使用该reduce功能.但是,该属性是动态计算的,它看起来更像是:

Thing t = items.stream()
        .reduce((left, right) -> {
            long leftValue = valueFunction.apply(left);
            long rightValue = valueFunction.apply(right);
            return leftValue > rightValue ? left : right;
        })
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

valueFunction现在需要将近一倍,而调用.

其他明显的迂回解决方案是:

  1. 将对象存储在带有索引的元组中
  2. 将对象存储在具有计算值的元组中
  3. 事先颠倒列表
  4. 不要使用Streams

jvd*_*dmr 7

从比较器中删除equals选项(如果比较的数字相等则不返回0,返回-1)(即编写不包含equals选项的比较器):

Thing t = items.stream()
        .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

  • 我不确定java是否保证比较器"按顺序"调用,即后面的项始终是第二个参数(考虑并行执行).话虽如此,在这个实现细节中放置一点信任是有意义的. (3认同)
  • 我确实认为这不能保证工作,因为你期望流并行/异步的时刻. (3认同)
  • 这和“等于”有什么关系?唯一的技巧似乎是将平局打破规则从“ a除非b更大”改为“ b b除非a更大”,这与OP的“ reduce”完全相同,但是恕我直言,在返回时不那么可读+/- 1`,而不是实际要保留的对象。同样,这也会比必要时更多地调用“ getI”(就像“ reduce”一样频繁)。 (2认同)

Nam*_*man 5

从概念上讲,您似乎可能正在寻找诸如thenComparing使用index列表中元素的 之类的东西:

Thing t = items.stream()
        .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

  • 这不是给整个事情 O(n²) 复杂度吗?此外,不适用于纯流,没有支持列表(不是要求,但无论如何)。像 Python 的 `enumerate` 这样的东西在这里会派上用场。 (7认同)
  • 你是对的。不幸的是,我没有写“equals”。 (2认同)