在一行中获取流/列表的最后一个元素 [英] Get last element of Stream/List in a one-liner

查看:162
本文介绍了在一行中获取流/列表的最后一个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在以下代码中获取流或列表的最后一个元素?

How can I get the last element of a stream or list in the following code?

其中 data.careas 列表< CArea>

CArea first = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal).findFirst().get();

CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal).collect(Collectors.toList()).; //how to?

正如你所看到的那样获得第一个元素,带有某个过滤器,并不难。

As you can see getting the first element, with a certain filter, is not hard.

然而,获得单行中的最后一个元素是一个真正的痛苦:

However getting the last element in a one-liner is a real pain:


  • 我似乎无法直接从 Stream 获取它。 (它只对有限的流有意义)

  • 似乎你不能得到像 first()和<$ c这样的东西$ c> last()来自 List 界面,真的很痛苦。

  • It seems I cannot obtain it directly from a Stream. (It would only make sense for finite streams)
  • It also seems that you cannot get things like first() and last() from the List interface, which is really a pain.

我没有看到任何关于不提供 first() last() List 界面中的$ c>方法,因为其中的元素是有序的,而且大小已知。

I do not see any argument for not providing a first() and last() method in the List interface, as the elements in there are ordered, and moreover the size is known.

但根据原始答案:如何获得有限的最后一个元素?

But as per original answer: How to get the last element of a finite Stream?

就个人而言,这个是我能得到的最接近的:

Personally, this is the closest I could get:

    int lastIndex = data.careas.stream()
            .filter(c -> c.bbox.orientationHorizontal)
            .mapToInt(c -> data.careas.indexOf(c)).max().getAsInt();
    CArea last = data.careas.get(lastIndex);

但是它确实涉及使用 indexOf 每个元素,这很可能不是你通常想要的,因为它会影响性能。

However it does involve using an indexOf on every element, which is most likely not you generally want as it can impair performance.

推荐答案

有可能获得最后一个元素使用方法 Stream: :减少。以下列表包含一般情况的最小示例:

It is possible to get the last element with the method Stream::reduce. The following listing contains a minimal example for the general case:

Stream<T> stream = ...; // sequential or parallel stream
Optional<T> last = stream.reduce((first, second) -> second);

此实现适用于所有有序流(包括从解释的)。对于无序流,这是显而易见的原因未指定将返回哪个元素。

This implementations works for all ordered streams (including streams created from Lists). For unordered streams it is for obvious reasons unspecified which element will be returned.

该实现适用于顺序并行流。乍一看可能会令人惊讶,遗憾的是文档没有明确说明。但是,它是流的一个重要特性,我试图澄清它:

The implementation works for both sequential and parallel streams. That might be surprising at first glance, and unfortunately the documentation doesn't state it explicitly. However, it is an important feature of streams, and I try to clarify it:


  • 方法的Javadoc Stream :: reduce 状态,它约束执行顺序

  • Javadoc还要求累加器函数必须是关联非干扰无状态函数,用于组合两个值,这显然是lambda表达式的案例(第一,第二) - >第二个

  • 简化操作声明:流类有多种形式的常规缩减操作,称为 reduce() collect() [..]正确构造的reduce操作固有可并行化,只要用于处理元素的函数是associative 无状态

  • The Javadoc for the method Stream::reduce states, that it "is not constrained to execute sequentially".
  • The Javadoc also requires that the "accumulator function must be an associative, non-interfering, stateless function for combining two values", which is obviously the case for the lambda expression (first, second) -> second.
  • The Javadoc for reduction operations states: "The streams classes have multiple forms of general reduction operations, called reduce() and collect() [..]" and "a properly constructed reduce operation is inherently parallelizable, so long as the function(s) used to process the elements are associative and stateless."

该文件密切相关的收藏家更加明确: 为确保顺序并行执行生成等效结果,收集器函数必须满足标识并且associativity 约束。

The documentation for the closely related Collectors is even more explicit: "To ensure that sequential and parallel executions produce equivalent results, the collector functions must satisfy an identity and an associativity constraints."

回到原始问题:以下代码存储对变量 last 如果流为空,则抛出异常。复杂度在流的长度上是线性的。

Back to the original question: The following code stores a reference to the last element in the variable last and throws an exception if the stream is empty. The complexity is linear in the length of the stream.

CArea last = data.careas.stream()
    .filter(c -> c.bbox.orientationHorizontal)
    .reduce((first, second) -> second).get();

这篇关于在一行中获取流/列表的最后一个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆