当前位置: 首页 > 知识库问答 >
问题:

使用Stream从List中查找匹配昂贵条件的最后一个元素

斜单鹗
2023-03-14

我有一个大约一百万个元素的有序列表,我正在寻找与特定条件匹配的最后一个元素,但是条件计算起来很重,所以如果我从头开始会更好。总是有大致的 log(n) 匹配元素,最小值为 1。

我可以手动操作:

List<Element> elements = ...;
Element element = null;
for (var it = elements.listIterator(elements.size()); it.hasPrevious(); ) {
  var candidate = it.previous();
  if (heavyConditionPredicate.test(candidate)) {
    element = candidate;
    break;
  }
}

有没有办法用< code>Streams来写这个,这样< code > heavyConditionPredicate 就不用对列表的每个元素进行测试了?如果heavyConditionPredicate计算起来不那么重,我会使用其他方法,但我没有那么幸运。

注意,< code>elements可以是任何类型的< code>List,我得到的那个不一定实现< code>RandomAccess,所以通过它们的索引访问列表可能也是代价很高的。

共有2个答案

郭炳
2023-03-14

Stream的当前实现(从Java11开始)的缺点是它不允许以相反的顺序处理项目。您必须为其提供具有指定顺序的源:

List<Element> elements = new ArrayList<>();
List<Element> reversedElements = new ArrayList<>(elements);
Collections.reverse(reversedElements);

Element element =  reversedElements.stream().filter(heavyConditionPredicate).findFirst().orElse(null);

另一种方法是利用Deque接口的优势,该接口提供Deque::descendingIterator

Deque<Element> elements = new ArrayDeque<>();
Iterator<Element> it = elements.descendingIterator()

使用Deque::推送,您可以创建一个自定义StreamUtils方法来反转传递的Stream,而无需使用外部库:

class StreamUtils {
    static <T> Stream<T> reverse(Stream<T> stream) {
        Deque<T> deque = new ArrayDeque<>();
        stream.forEach(deque::push);
        return deque.stream();
    }
}

...

Element element = StreamUtils.reverse(elements.stream())
    .filter(heavyConditionPredicate)
    .findFirst().orElse(null);
柯振濂
2023-03-14

Guava的< code>Lists::reverse在这里肯定有帮助,因为它是一个视图,它不修改我的列表,也不通过索引访问元素:

Lists.reverse(elements).stream()
  .filter(heavyConditionPredicate)
  .findFirst();
 类似资料:
  • 问题内容: 如何在以下代码中获取流或列表的最后一个元素? 哪里是: 如您所见,获得第一个元素一定并不困难。 但是,获得单线的最后一个元素确实是一个痛苦: 看来我无法直接从。(仅对有限的流有意义) 这似乎也不能得到像和从接口,这实在是一种痛苦。 我看不到在接口中不提供and 方法的任何参数,因为其中的元素是有序的,而且大小是已知的。 但是按照原始答案:如何获得有限的最后一个元素? 就个人而言,这是我

  • 问题内容: 我的情况是: 我想知道是否有一个名字和年龄相同但不在乎的人。 什么是最快的方法? 问题答案: 为自己定义一个关键对象,该对象可以保存并比较所需的属性。在这种简单情况下,您可以使用一个小的列表,而每个索引对应一个属性。对于更复杂的情况,可以使用(使用属性名称作为键)或专用类: 具有这种映射功能。您可以使用简单的解决方案: 当您的列表很大时,这可能会导致性能不佳。如果列表很大(或者无法预测

  • 如何在下面的代码中获取流或列表的最后一个元素? 其中是: 正如您所看到的,使用特定的获取第一个元素并不难。 null 我看不出在接口中没有提供和方法的任何理由,因为其中的元素是有序的,而且大小是已知的。 但正如最初的答案:如何获得有限的最后一个元素? 就我个人而言,这是我能得到的最接近的结果:

  • 问题内容: 我想匹配字符串中最后一次出现的简单模式,例如 但是,如果字符串 很 长,则会生成大量匹配项。有没有更直接的方法来匹配第二次出现的“ AAAA”,还是应该使用此替代方法? 问题答案: 您可以使用表示行末字符: 另外,请注意,这是变量的坏名称,因为它隐藏了内置类型。要访问列表的最后一个元素,您可以使用index: