如何基于比较连续的列表元素将Java流减少为布尔值

如何基于比较连续的列表元素将Java流减少为布尔值,java,functional-programming,reduce,collectors,Java,Functional Programming,Reduce,Collectors,作为一个重构练习,我尝试采取如下方式: for (int i = 1; i < orderedList.size(); i++) { Object object1 = ordered.get(i - 1); Object object2 = ordered.get(i); if (isDifferent(object1, object2)) return true; } return false; for(int

作为一个重构练习,我尝试采取如下方式:

    for (int i = 1; i < orderedList.size(); i++) {
        Object object1 = ordered.get(i - 1);
        Object object2 = ordered.get(i);
        if (isDifferent(object1, object2)) return true;
    }

    return false;
for(int i=1;i
转换为一个简单的Java函数语句。乍一看,我是按顺序处理列表中的元素,所以
reduce()
听起来很有希望,但是

  • 它需要携带一个布尔值,这会丢失上一个元素;或
  • 继续使用列表的前一个元素,这意味着我需要将它放在某种包装器对象中,或者笨拙地使用
    Optional
    或另一个
    list
    作为包装器,以便跟踪我是否有差异
  • 所以,我看到了使用reduce操作的方法,但是它比for循环更复杂,更难理解

    我考虑过创建一个自定义收集器,但遇到了同样的问题

    这是对reduce的正确使用,还是因为我知道可以使用reduce对上一次迭代处理顺序值而受到诱惑?如果这是一个正确的用法,我如何组合函数以将自己简化为布尔值


    感谢您提供此思考练习的帮助。

    因为您正在使用for循环索引两个
    列表
    s,您可以将其替换为,并使用以下内容减少:


    虽然,我并不认为这有什么好处,因此将其作为for循环可能更具可读性。

    这里的基本操作称为“压缩”:给定两个
    a
    s和
    B
    s流以及一个组合运算符
    (a,B)->C
    ,您可以创建
    C
    流(截短到较短的输入流)。假设您有这样一个函数

    <A, B, C> Stream<C> zip
     (Stream<? extends A> as, Stream<? extends B> bs,
      BiFunction<? super A, ? super B, ? extends C> combine);
    
    标准库中没有
    zip
    。如果您使用的是像Guava这样的东西,您可以检查它是否有此操作,例如..或者,您可以自己实现它并将其粘贴到某个实用程序类中,此时您可能需要。我将重现此处列出的代码(这似乎是从实际Streams API的测试版复制而来):


    publicstaticstreamzip(Stream从您的逻辑来看,它不是这么简单吗

    return orderedList.stream.distinct().count() != 1; // assuming that you have equals and 
                                                      //  hashcode method overridden for 
                                                      // your object.
    

    流适合孤立地处理每个元素,或者减少时处理相邻元素。您可以“滥用”模式是通过读取/写入流外的变量来实现的,但在这一点上,你最好使用一个老式的循环。离开它有什么不对?流将剥夺你短路的可能性。因此,从性能角度看,你在流中的表现会更差,除非
    isDifferent
    计算结果为
    true
    exce非常罕见。就可读性而言,你已经看到它的效果不好。@Bohemian Reduce并没有定义为处理相邻元素的操作;它需要关联函数,因此可能会处理,例如
    (a×b)×(c×d)
    ,这不适合OP的任务。您必须将所有元素映射到包含间隔(第一个和最后一个元素)和布尔状态的类型。除此之外,您还将失去短路……事实上,我有点喜欢这样。我正试图摆脱“I-1”使用reduce操作,当我在一个
    forEach
    中插入i+1/i-1时,它看起来比原来的更糟糕,但即使使用手动索引,它也更可读。没有想过将同一个列表压缩到自身中,也没有意识到任何(相对)标准库支持zip。谢谢!
    zip(ordered.stream(), ordered.stream().skip(1), this::isDifferent).anyMatch(x -> x);
    // ordered: a b c d ... y z
    // skipped: b c d ... y z
    // zipped : (a, b) (b, c) (c, d) ... (y, z)
    
    public static<A, B, C> Stream<C> zip(Stream<? extends A> a,
                                         Stream<? extends B> b,
                                         BiFunction<? super A, ? super B, ? extends C> zipper) {
        Objects.requireNonNull(zipper);
        Spliterator<? extends A> aSpliterator = Objects.requireNonNull(a).spliterator();
        Spliterator<? extends B> bSpliterator = Objects.requireNonNull(b).spliterator();
    
        // Zipping looses DISTINCT and SORTED characteristics
        int characteristics = aSpliterator.characteristics() & bSpliterator.characteristics() &
                ~(Spliterator.DISTINCT | Spliterator.SORTED);
    
        long zipSize = ((characteristics & Spliterator.SIZED) != 0)
                ? Math.min(aSpliterator.getExactSizeIfKnown(), bSpliterator.getExactSizeIfKnown())
                : -1;
    
        Iterator<A> aIterator = Spliterators.iterator(aSpliterator);
        Iterator<B> bIterator = Spliterators.iterator(bSpliterator);
        Iterator<C> cIterator = new Iterator<C>() {
            @Override
            public boolean hasNext() {
                return aIterator.hasNext() && bIterator.hasNext();
            }
    
            @Override
            public C next() {
                return zipper.apply(aIterator.next(), bIterator.next());
            }
        };
    
        Spliterator<C> split = Spliterators.spliterator(cIterator, zipSize, characteristics);
        return (a.isParallel() || b.isParallel())
               ? StreamSupport.stream(split, true)
               : StreamSupport.stream(split, false);
    }
    
    return orderedList.stream.distinct().count() != 1; // assuming that you have equals and 
                                                      //  hashcode method overridden for 
                                                      // your object.