Java streams – filter previously filtered values

I am trying to use Java streams and try to find out the possible contents and their advantages and disadvantages At present, I am trying to use streams to implement Eratosthenes's sieve, but it seems that I can't find a good way to recycle the previously filtered values without storing them in a separate collection

I want to accomplish something like this:

IntStream myStream = IntStream.range(0,3);
myStream.filter(s -> {
    System.out.print("[filtering "+s+"] ");
    myStream.forEach(q -> System.out.print(q+","));
    System.out.println();
    return true; //eventually respond to values observed on the line above
});

With required output:

[filtering 0] 
[filtering 1] 0,[filtering 2] 0,1,[filtering 3] 0,2,

Note that when filtering each new value, all previously filtered values are observed This makes it easy to implement Eratosthenes's sieve, because I can filter out all non prime values and check the divisibility of all numbers previously passed through the prime filter for each new value

However, the above example gives an error in NetBeans:

local variables referenced from a lambda expression must be final or effectively final

This seems to be because I refer to mystream in the filter that has been applied to mystream Is there any good way to resolve this error (that is, make a final copy of the stream containing only the values filtered so far), or is there a better way to resolve this problem without using a separate collection to store values?

Solution

I managed to create an infinite stream of prime numbers using eratoshenes's sieve, but it didn't actually use past values Instead, it removes the multiples of prime numbers in the tail (in a lazy way, because the tail is infinite), just like sieve of the original Eratosthenes algorithm To do this, I use iterator as a helper (because stream can only be used once) and implement lazyconcat. For the stream

class StreamUtils {
    public static IntStream fromIterator(PrimitiveIterator.OfInt it) {
        return StreamSupport.intStream(
                Spliterators.spliteratorUnkNownSize(it,Spliterator.ORDERED),false);
    }

    public static IntStream lazyConcat(supplier<IntStream> a,supplier<IntStream> b) {
        return StreamSupport.intStream(new Spliterator.OfInt() {
            boolean beforeSplit = true;
            Spliterator.OfInt spliterator;

            @Override
            public OfInt trySplit() {
                return null;
            }

            @Override
            public long estimateSize() {
                return Long.MAX_VALUE;
            }

            @Override
            public int characteristics() {
                return Spliterator.ORDERED;
            }

            @Override
            public boolean tryAdvance(IntConsumer action) {
                boolean hasNext;
                if (spliterator == null) {
                    spliterator = a.get().spliterator();
                }
                hasNext = spliterator.tryAdvance(action);
                if (!hasNext && beforeSplit) {
                    beforeSplit = false;
                    spliterator = b.get().spliterator();
                    hasNext = spliterator.tryAdvance(action);
                }
                return hasNext;
            }
        },false);
    }
}

My Eratosthenes stream filter looks like this:

class Primes {
    public static IntStream stream() {
        return sieve(IntStream.iterate(2,n -> n + 1));
    }

    private static IntStream sieve(IntStream s) {
        PrimitiveIterator.OfInt it = s.iterator();
        int head = it.nextInt();
        IntStream tail = StreamUtils.fromIterator(it);
        return StreamUtils.lazyConcat(
                () -> IntStream.of(head),() -> sieve(tail.filter(n -> n % head != 0)));
    }
}

Then we can use it like this:

System.out.println(Primes.stream().limit(20).@R_360_2419@ed().collect(Collectors.toList()));

Output:

I think it's a good exercise, but it seems inefficient and doesn't fit the stack at all

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>