java 流:查找相邻值匹配的最简单方法

问题描述 投票:0回答:5

如何将这个迭代代码块转换为流?

Integer prev = -1;
boolean adjacentPair = false;

for(Integer num : numberList) {
    if (num.equals(prev)) {
        adjacentNumberSame = true;
        break;
    }
    prev = num;
}
return adjacentNumberSame 
java java-stream
5个回答
4
投票

这是一种(不是很好)的方法:

IntStream.range(1, numberList.size())
         .anyMatch(i -> numberList.get(i).equals(numberList.get(i-1)));

如果您的

numberList
ArrayList
或类似的东西,那么它的复杂性是可以接受的。如果没有,你最好使用
iterator
。像这样:

var Iter = list.stream().iterator();
var res = list.stream()
              .skip(1)
              .map(v -> v.equals(Iter.next()) )
              .anyMatch(v -> v)
              ;

更优雅的方式需要一些具有

zip
功能的第三方库。使用
zip
它可以看起来像:

var res = zip(
              list.stream().skip(1),
              list.stream(),
              (a, b) -> a.equals(b)
          ).anyMatch(x->x);

或者您可以编写自己的

zip
。像这样的东西:

public static <A,B,C> Stream<C> zip(Stream<A> listA, Stream<B> listB, BiFunction<A,B,C> zipper){
    var iB = listB.iterator();
    return listA.filter( a -> iB.hasNext())
                .map( a -> zipper.apply(a, iB.next()) );
}

PS。我不会推荐

reduce
,因为它在 @vbezhenar 的答案中使用。因为它不会短路,正如您在这里看到的那样https://repl.it/repls/DisastrousWideRevisioncontrol(寻找异常)


4
投票

可以使用reduce操作。示例代码:

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 2, 3);
    class Result {
        boolean adjacentPair = false;
        Integer prevItem = null;
    }
    boolean adjacentPair = list.stream().reduce(new Result(),
            (result, item) -> {
                result.adjacentPair = result.adjacentPair || item.equals(result.prevItem);
                result.prevItem = item;
                return result;
            },
            (result1, result2) -> {
                throw new UnsupportedOperationException();
            }
    ).adjacentPair;
    System.out.println(adjacentPair);
}

Result
保存中间结果。
adjacentPair
字段指示是否遇到相邻对。
prevItem
字段保存在下一次迭代中进行比较的前一项的值。该函数的第三个参数是组合器,它用于并行流,此示例适用于串行流。


1
投票

流不是正确的出路。这是一个非常笼统的说法。

这里的一个特殊问题是你不能折叠和短路

我想出的streamy解决方案与@vbezhenar类似,除了它表现良好(有组合器)并且没有引入累加器类。

    // Accumulator is: { leftElement, match, rightElement }
    //    (Could introduce a record.)
    // States of the accumulator are:
    //    { null null null } - initial
    //    { x null x } - first element
    //    { x m null } - found match m
    //    { x null y } - no matches found
    Integer[] result = numberList.stream().<Integer[]>collect(
        // supplier
        () -> new Integer[3],
        // accumulator
        (acc,t) -> {
            if (acc[0] == null) {
                // First into acc.
                acc[0] = acc[2] = t;
            } else if (acc[1] != null) {
                // Already found pair to the left.
            } else if (t.equals(acc[2])) {
                // Found first pair.
                acc[1] = t;
                acc[2] = null;
            } else {
                // Otherwise, t replaces rightmost.
                acc[2] = t;
            }
        },
        // combiner
        (acc, other) -> {
            if (acc[1] != null) {
                // Alread found pair to the left.
            } else if (acc[2] == null) {
                // Necessary anyone? Empty acc is combined.
                acc[0] = other[0];
                acc[1] = other[1];
                acc[2] = other[2];
            } else if (acc[2].equals(other[0])) {
                // Found match.
                acc[1] = acc[2];
                acc[2] = null;
            } else {
                // Otherwise, leftmost element with rest as other acc.
                acc[1] = other[1];
                acc[2] = other[2];
            }
        }
    );
    return result[1] != null;

我还没有实际测试过组合器。我怀疑大多数组合器也从未经过测试

如果我们像 @vbezhenar 那样对流行为做出类似的假设,那么

dropWhile
就是我们的 Johnny 5 朋友。

    return numberList.stream().dropWhile(new Predicate<>() {
        Integer last;
        public boolean test(Integer t) {
            Integer lastLast = last;
            last = t;
            return !t.equals(lastLast);
        }
    }).findFirst().isPresent();

匿名内部类!!


0
投票

您不需要做所有这些。为你的方法主体实现这个:

return numberList.contains(prev);

例如,您可以:

public boolean adjacentNumberIsSame(int currentValue, ArrayList<Integer> numberList){
    return numberList.contains(currentValue);
}

0
投票

即将推出的 Java 24 中的

windowSliding
收集器可用于将流分组为相邻元素对。 然后可以检查每一对,看看两个值是否相同。

boolean adjacentNumberSame = numberList.stream()
        .gather(Gatherers.windowSliding(2))
        .anyMatch(w -> w.getFirst().equals(w.getLast()));
© www.soinside.com 2019 - 2024. All rights reserved.