【问题标题】:Java 8 Stream: How to compare current element with next element?Java 8 Stream:如何比较当前元素和下一个元素?
【发布时间】:2015-11-14 06:21:43
【问题描述】:

如何使用 Java 8 Streams 从 List 获取下一个元素?

如果我正在迭代 List,我想将当前元素与列表的下一个元素进行比较。

使用 Java 8 Stream 是否可行?

【问题讨论】:

  • 如何迭代?你如何确定当前和下一个元素?为什么您觉得有必要对流进行此操作?
  • 我的目标是比较列表中的两个连续元素,或者我想检查它们是否相等。
  • 这是一项任务,而不是一个目标。你这样做一定是有原因的。例如。如果两个元素相等,您想做某事。有趣的是如何使用流来做这件事。已经以类似的形式提出过这个问题。

标签: java java-8 java-stream


【解决方案1】:

我的免费StreamEx 库允许您使用额外的pairMap 中间操作来处理流元素对。像这样:

StreamEx.of(input).pairMap((current, next) -> doSomethingWith(current, next));

其中inputCollection、数组或Stream。例如,通过这种方式,您可以轻松检查输入是否已排序:

boolean isSorted = StreamEx.of(input)
                           .pairMap((current, next) -> next.compareTo(current))
                           .allMatch(cmp -> cmp >= 0);

还有forPairs 终端操作,这是对所有输入元素对的forEach 模拟:

StreamEx.of(input).forPairs((current, next) -> doSomethingWith(current, next));

这些功能可以很好地与任何流源(无论是否随机访问)配合使用,并且完全支持并行流。

【讨论】:

  • 太棒了。感谢您的解释。
【解决方案2】:

一种方法是生成索引的IntStream,并通过索引获取List 元素。这仅在List 支持随机访问时才有效(即,如果您的ListLinkedList,这将是一个坏主意,因为list.get(i) 不需要固定时间)。

例如:

IntStream.range(0,list.size()-1).forEach(i -> {
    doSomething(list.get(i),list.get(i+1));
});

另一种方法是将最后一个元素存储在数组中:

List<Element> list = ...
Element[] arr = new Element[1];
list.stream().forEach(e -> {
    if (arr[0] != null)
        doSomething(arr[0],e); 
    arr[0]=e;
});

这仅适用于顺序流。

【讨论】:

  • 流中有没有办法跳过下一次迭代,即在某些情况下将 forEach 索引增加到 i+2 而不是 i+1?
  • @Stacky 您可以使用IntStream.iterate 来实现类似于 for 循环的行为,并将计数器增加您希望的任何值。例如:IntStream.iterate (1, i -&gt; i &lt; 10, i -&gt; i + 2).forEach (System.out::println);
  • 如果我需要有条件地增加 i 怎么办?例如:SomeClass classLevelObj = new SomeClass(); IntStream.iterate (1, i -&gt; i &lt; 10, i -&gt; i + 1).forEach (if(classLevelObj.cond) i+=2 else i+=3);
【解决方案3】:

Stream.reduce 可以使用,具体取决于目标。正如你所说,你想比较连续的元素,下面会打印“Same 3”:

Stream.of(1,2,3,3).reduce((a,b)->{
    if(a==b) System.out.println("Same "+a);
    return b; // will be "a" for next reduction
});

【讨论】:

  • 一个例子可能会有所帮助:)
【解决方案4】:

例如,如果您有一个整数列表并想检查它们是否按升序排序,您可以执行以下操作:

@Test
public void test_listIsSorted() {

    // create integer list for testing purposes: 0,1,2,3, .., 10
    List<Integer> integerList = IntStream.range(0, 10)
            .boxed()
            .collect(Collectors.toList());

    // stream list and compare item n with n+1
    integerList.stream()
            .reduce((integer1, integer2) -> {
                assert integer1 < integer2 : "ordering must be ascending";
                // return second value (which will be processed as "integer1" in the next iteration
                return integer2;
            });

}

这将比较以下对:(0,1),(1,2),...

【讨论】:

    【解决方案5】:

    您总是执行以下操作之一:

    1. 将您的流转换为包含流中最后几个元素的“历史”的元素流
    2. 以这样一种方式处理您的流,即当前处理的元素被视为“下一个”元素,之前处理的元素被视为“当前”元素。

    这两种解决方案的实现都可以在这个帖子中看到:Is it possible to get next element in the Stream?

    【讨论】:

      【解决方案6】:

      我必须这样做并比较流(最初是数组)元素的差异。 所以我使用了一个方法作为 UnaryOperator 的参数,.map() 期望如下......它对我有用,没有任何特殊的小发明:

      import java.util.Arrays;
      
      class streamDiffUtil {
          public static void main(String[] args) {
              int[] elements = {1,2,5};
              int result = Arrays.stream(elements)
                      .map(value -> calcMaxDiff(value, elements))
                      .max()
                      .getAsInt();
              System.out.println(result);
          }
      
          private static int calcMaxDiff(int j, int[] elements) {
              return Arrays.stream(elements)
                      .map(value -> Math.abs(j-value))
                      .max().getAsInt();
          }
      }
      

      最好知道方法 calcMaxDiff 如何等同于 .map 签名中的 UnaryIntOperator。这有点超出我的想象。 希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-26
        • 1970-01-01
        • 2020-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多