Java 8 Stream, getting head and tail

后端 未结 9 2068
太阳男子
太阳男子 2020-11-30 05:40

Java 8 introduced a Stream class that resembles Scala\'s Stream, a powerful lazy construct using which it is possible to do something like this very concisely:



        
9条回答
  •  遥遥无期
    2020-11-30 06:19

    If you don't mind using 3rd party libraries cyclops-streams, I library I wrote has a number of potential solutions.

    The StreamUtils class has large number of static methods for working directly with java.util.stream.Streams including headAndTail.

    HeadAndTail headAndTail = StreamUtils.headAndTail(Stream.of(1,2,3,4));
    int head = headAndTail.head(); //1
    Stream tail = headAndTail.tail(); //Stream[2,3,4]
    

    The Streamable class represents a replayable Stream and works by building a lazy, caching intermediate data-structure. Because it is caching and repayable - head and tail can be implemented directly and separately.

    Streamable replayable=  Streamable.fromStream(Stream.of(1,2,3,4));
    int head = repayable.head(); //1
    Stream tail = replayable.tail(); //Stream[2,3,4]
    

    cyclops-streams also provides a sequential Stream extension that in turn extends jOOλ and has both Tuple based (from jOOλ) and domain object (HeadAndTail) solutions for head and tail extraction.

    SequenceM.of(1,2,3,4)
             .splitAtHead(); //Tuple[1,SequenceM[2,3,4]
    
    SequenceM.of(1,2,3,4)
             .headAndTail();
    

    Update per Tagir's request -> A Java version of the Scala sieve using SequenceM

    public void sieveTest(){
        sieve(SequenceM.range(2, 1_000)).forEach(System.out::println);
    }
    
    SequenceM sieve(SequenceM s){
    
        return s.headAndTailOptional().map(ht ->SequenceM.of(ht.head())
                                .appendStream(sieve(ht.tail().filter(n -> n % ht.head() != 0))))
                        .orElse(SequenceM.of());
    }
    

    And another version via Streamable

    public void sieveTest2(){
        sieve(Streamable.range(2, 1_000)).forEach(System.out::println);
    }
    
    Streamable sieve(Streamable s){
    
        return s.size()==0? Streamable.of() : Streamable.of(s.head())
                                                        .appendStreamable(sieve(s.tail()
                                                                        .filter(n -> n % s.head() != 0)));
    }
    

    Note - neither Streamable of SequenceM have an Empty implementation - hence the size check for Streamable and the use of headAndTailOptional.

    Finally a version using plain java.util.stream.Stream

    import static com.aol.cyclops.streams.StreamUtils.headAndTailOptional;
    
    public void sieveTest(){
        sieve(IntStream.range(2, 1_000).boxed()).forEach(System.out::println);
    }
    
    Stream sieve(Stream s){
    
        return headAndTailOptional(s).map(ht ->Stream.concat(Stream.of(ht.head())
                                ,sieve(ht.tail().filter(n -> n % ht.head() != 0))))
                        .orElse(Stream.of());
    }
    

    Another update - a lazy iterative based on @Holger's version using objects rather than primitives (note a primitive version is also possible)

      final Mutable> predicate = Mutable.of(x->true);
      SequenceM.iterate(2, n->n+1)
               .filter(i->predicate.get().test(i))
               .peek(i->predicate.mutate(p-> p.and(v -> v%i!=0)))
               .limit(100000)
               .forEach(System.out::println);
    

提交回复
热议问题