如何使用 Java 8 流查找较大值之前的所有值?用例

2022-09-01 04:23:56

用例

通过在工作中发布的一些编码Katas,我偶然发现了这个我不知道如何解决的问题。

使用 Java 8 Streams,给定一个正整数列表,生成一个整数列表,其中整数在较大的值之前。

[10, 1, 15, 30, 2, 6]

上述输入将产生:

[1, 15, 2]

因为 1 先于 15,15 先于 30,2 先于 6。

非流解决方案

public List<Integer> findSmallPrecedingValues(final List<Integer> values) {

    List<Integer> result = new ArrayList<Integer>();
    for (int i = 0; i < values.size(); i++) {
        Integer next = (i + 1 < values.size() ? values.get(i + 1) : -1);
        Integer current = values.get(i);
        if (current < next) {
            result.push(current);
        }
    }
    return result;
}

我尝试过什么

我遇到的问题是我不知道如何在lambda中访问下一个。

return values.stream().filter(v -> v < next).collect(Collectors.toList());

问题

  • 是否可以检索流中的下一个值?
  • 我应该使用并映射到 a 才能访问下一个吗?mapPair

答案 1

使用 IntStream.range

static List<Integer> findSmallPrecedingValues(List<Integer> values) {
    return IntStream.range(0, values.size() - 1)
        .filter(i -> values.get(i) < values.get(i + 1))
        .mapToObj(values::get)
        .collect(Collectors.toList());
}

它当然比具有大循环的命令式解决方案更好,但就以惯用方式“使用流”的目标而言,它仍然有点meh。

是否可以检索流中的下一个值?

不,不是真的。据我所知,最好的引用是在java.util.stream包描述中:

在流的生命周期中,流的元素只访问一次。就像 一个 ,必须生成一个新的流来重新访问源的相同元素。Iterator

(除了正在操作的当前元素之外,检索元素意味着可以多次访问它们。

从技术上讲,我们也可以通过其他几种方式做到这一点:

  • 有条不紊地(非常嗯)。
  • 从技术上讲,使用流仍在使用流。iterator

答案 2

这不是一个纯粹的Java8,但最近我发布了一个名为StreamEx的小型库,它有一个完全用于此任务的方法:

// Find all numbers where the integer preceded a larger value.
Collection<Integer> numbers = Arrays.asList(10, 1, 15, 30, 2, 6);
List<Integer> res = StreamEx.of(numbers).pairMap((a, b) -> a < b ? a : null)
    .nonNull().toList();
assertEquals(Arrays.asList(1, 15, 2), res);

使用自定义拆分器在内部实现的 pairMap 操作。因此,您拥有非常干净的代码,它不依赖于源代码是还是其他任何东西。当然,它也适用于并行流。List

为此任务提交了一个测试用例


推荐