How to match stream elements but return false if non exists?

后端 未结 6 1718
无人共我
无人共我 2020-12-09 11:58

I have a stream and would like to check if all match a filter. If all match, return true.

But, if the stream is empty, I\'d like to return false

相关标签:
6条回答
  • 2020-12-09 12:28
    return !stream.filter(Whatever::someCheck).collect(Collectors.toList()).isEmpty()
    
    0 讨论(0)
  • 2020-12-09 12:29

    I already added two answers I now removed but the problem kept nagging on me so I gave it a third try and this time it works including keeping allMatch. Here is the code for method validate.

    public static boolean validate(Stream<Whatever> stream) {
        final boolean[] streamNotEmpty = new boolean[1];
        return stream.filter(elem -> {
            streamNotEmpty[0] = true;
            return true;
        }).allMatch(Whatever::someCheck) && streamNotEmpty[0];
    }
    

    A shorter version would be

    public static boolean validate(Stream<Whatever> stream) {
        final boolean[] streamNotEmpty = new boolean[1];
        return stream.allMatch(elem -> {
            streamNotEmpty[0] = true;
            return elem.someCheck();
        }) && streamNotEmpty[0];
    }
    

    The idea behind this is that we want to know if there was at least one element in the stream, so I created a final boolean[] where the value is changed within the filter-call. So at the end of the stream's processing we can check the stream for being empty or not and act accordingly when we return the result.

    Here is a complete class including testcases to prove that - this time finally - I provided a valid solution.

    import java.util.ArrayList;
    import java.util.stream.Stream;
    
    public class StreamTest {
    
        public static boolean validate(Stream<Whatever> stream) {
            final boolean[] streamNotEmpty = new boolean[1];
            return stream.allMatch(elem -> {
                streamNotEmpty[0] = true;
                return elem.someCheck();
            }) && streamNotEmpty[0];
        }
    
        static class Whatever {
            private boolean checkResult;
    
            public Whatever() {
                this(false);
            }
    
            public Whatever(boolean b) {
                this.checkResult = b;
            }
    
            public boolean someCheck() {
                return checkResult;
            }
        }
    
        public final static void main(String[] args) {
            ArrayList<Whatever> list = new ArrayList<>();
            System.out.println("empty list: " + validate(list.stream()));
            System.out.println("empty list parallel: " + validate(list.parallelStream()));
    
            for (int i = 0; i < 10000; i++) {
                list.add(new Whatever(true));
            }
    
            System.out.println("non empty true list: " + validate(list.stream()));
            System.out.println("non empty true list parallel: " + validate(list.parallelStream()));
    
            for (int i = 0; i < 10000; i += 1000) {
                list.add(new Whatever(false));
            }
    
            System.out.println("non empty false list: " + validate(list.stream()));
            System.out.println("non empty false list parallel: " + validate(list.parallelStream()));
        }
    }
    

    The output when executing it is:

    empty list: false empty list parallel: false non empty true list: true non empty true list parallel: true non empty false list: false non empty false list parallel: false

    0 讨论(0)
  • 2020-12-09 12:30

    You could use

    public boolean validate(Stream<Whatever> stream) {
        return stream.map(Whatever::someCheck).reduce(Boolean::logicalAnd).orElse(false);
    }
    

    which expresses the intent. We map each element to a boolean value expressing whether it matches and reducing all of them with a logical and operation which will yield true iff all of them were true. reduce will return an empty Optional if there were no elements, which we map to false using orElse(false), as intended.

    The only disadvantage is that this is non short-circuiting, i.e. does not stop immediately at the first non-matching element.

    A solution still supporting short-circuiting might be a bit more evolved:

    public boolean validate(Stream<Whatever> stream) {
        boolean parallel = stream.isParallel();
        Spliterator<Whatever> sp = stream.spliterator();
        if(sp.getExactSizeIfKnown() == 0) return false;
        Stream.Builder<Whatever> b = Stream.builder();
        if(!sp.tryAdvance(b)) return false;
        return Stream.concat(b.build(), StreamSupport.stream(sp, parallel))
            .allMatch(Whatever::someCheck);
    }
    

    This is a variant of Eugene’s answer, but it doesn’t loose characteristics or parallelism and might be a bit more efficient in general.

    0 讨论(0)
  • 2020-12-09 12:52

    If you are OK with losing your characteristics and parallelism, this for example:

     public static boolean validate(Stream<String> stream) {
        Iterator<String> it = stream.iterator();
    
        if (!it.hasNext()) {
            return false;
        }
    
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, 0), false)
                .peek(System.out::println)
                .allMatch(x -> x.contains("a"));
    
    }
    
    0 讨论(0)
  • 2020-12-09 12:53

    The following code will work (I tested it).

    public static boolean validate(Stream<Whatever> stream) {
        return stream.reduce((whatever1, whatever2) -> Whatever.someCheck(whatever1) ? whatever2 : whatever1)
                .map(Whatever::someCheck).orElse(false);
    }
    

    How it works? We use reduce operation to check that every element matches the predicate, if it fails, we keep returning the failing one (in ternary operation). At the end, we map the reduced Whatever object to boolean, and if it's true: then all matched and this is not empty (orElse(false)).

    0 讨论(0)
  • 2020-12-09 12:55

    Try peek

    boolean[] flag = new boolean[1];
    return stream.peek(t -> flag[0] = true).allMatch(Whatever::someCheck) && flag[0]
    
    0 讨论(0)
提交回复
热议问题