Limit a stream by a predicate

前端 未结 19 3388
别跟我提以往
别跟我提以往 2020-11-21 22:54

Is there a Java 8 stream operation that limits a (potentially infinite) Stream until the first element fails to match a predicate?

In Java 9 we can use

19条回答
  •  孤城傲影
    2020-11-21 23:44

    Might be a bit off topic but this is what we have for List rather than Stream.

    First you need to have a take util method. This methods takes first n elements:

    static  List take(List l, int n) {
        if (n <= 0) {
            return newArrayList();
        } else {
            int takeTo = Math.min(Math.max(n, 0), l.size());
            return l.subList(0, takeTo);
        }
    }
    

    it just works like scala.List.take

        assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3, 4, 5), 3));
        assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3), 5));
    
        assertEquals(newArrayList(), take(newArrayList(1, 2, 3), -1));
        assertEquals(newArrayList(), take(newArrayList(1, 2, 3), 0));
    

    now it will be fairly simple to write a takeWhile method based on take

    static  List takeWhile(List l, Predicate p) {
        return l.stream().
                filter(p.negate()).findFirst(). // find first element when p is false
                map(l::indexOf).        // find the index of that element
                map(i -> take(l, i)).   // take up to the index
                orElse(l);  // return full list if p is true for all elements
    }
    

    it works like this:

        assertEquals(newArrayList(1, 2, 3), takeWhile(newArrayList(1, 2, 3, 4, 3, 2, 1), i -> i < 4));
    

    this implementation iterate the list partially for a few times but it won't add add O(n^2) operations. Hope that's acceptable.

提交回复
热议问题