javaalgorithmlambdajava-8java-stream

How to count the number of trailing zeroes in an integer using Java 8 Stream/Lambda?


How to count the number of trailing zeroes in an integer using Java 8 Stream/Lambda?

Basically the logic should be: keep the integer dividing by 10 as long as the remainder is 0 (the quotient will be supplied to the next division) and count the occurrence(s).

e.g.

12300 % 10 == 0 true

1230 % 10 == 0 true

123 % 10 == 0 false

Answer: 2

Note: I prefer not to involve String here :-)


Solution

  • If this is a purely hypothetical question, here is a purely hypothetical answer of how you can do it:

    static int countZeroes(int value) {
        if(value == 0) // we need to handle this case explicitly
            return 1; 
        IntStream s = IntStream.iterate(value, v -> v / 10);
        return (int) takeWhile(s, v -> v > 0 && v % 10 == 0)
                .count();
    
    }
    

    It uses a helper function takeWhile that is available in Java 9 but not in Java 8 so has to be emulated like this:

    // In Java 9 there is a standard takeWhile
    // https://docs.oracle.com/javase/9/docs/api/java/util/stream/Stream.html#takeWhile-java.util.function.Predicate-
    // but in Java 8 I have to emulate it
    static IntStream takeWhile(IntStream s, final IntPredicate pr) {
        final Spliterator.OfInt origSp = s.spliterator();
    
        Spliterator.OfInt filtered = new Spliterators.AbstractIntSpliterator(origSp.estimateSize(), 0) {
            boolean lastPredicate = true;
    
            @Override
            public boolean tryAdvance(final IntConsumer action) {
                if (!lastPredicate)
                    return false;
    
                origSp.tryAdvance((int v) -> {
                    lastPredicate = pr.test(v);
                    if (lastPredicate) {
                        action.accept(v);
                    }
                });
                return lastPredicate;
            }
        };
    
        return StreamSupport.intStream(filtered, false);
    }
    

    The idea is that

    IntStream.iterate(value, v1 -> v1 / 10).takeWhile(v -> v > 0)
    

    should generate a stream of cutting digits at the end one by one and then you can apply takeWhile(v -> v % 10 == 0).count() to count the number of zeros and finally you can merge those two takeWhiles into one.