Reputation: 16750
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 :-)
Upvotes: 2
Views: 498
Reputation: 40034
You can do it by just using the three argument IntStream.iterate
.
v%10
isolates the last digit of v
using the remainder operatorv/10
effectively removes last digit from v
Using the value under test as the seed.
0
, put it on the streamint[] testCases = {10222200,229999,22,1000000000,1010,-20000,-222};
for (int tc : testCases) {
long trailingZeroes = IntStream.iterate(tc, v->v%10==0, v->v/10)
.count();
System.out.printf("%10d : %2d%n", tc, trailingZeroes);
}
prints
10222200 : 2
229999 : 0
22 : 0
1000000000 : 9
1010 : 1
-20000 : 4
-222 : 0
Upvotes: 1
Reputation: 7917
Here's another way:-
private static int countTrailingZeroes(int n) {
int length = n == 0 ? 1 : (int) (Math.log10(n) + 1); //number of digits in n
return IntStream.rangeClosed(0, length)
.map(i -> length - i) //reverse stream
.map(o -> (int) Math.pow(10, o))
.filter(o -> n % o == 0)
.boxed()
.findFirst()
.map(i -> (int) Math.log10(i)) //number of digits minus 1
.orElse(0);
}
@Holger's edit:
private static int countTrailingZeroes(int n) {
int length = n == 0 ? 1 : (int) (Math.log10(n) + 1); //number of digits in n
return IntStream.rangeClosed(0, length)
.map(i -> length - i) //reverse stream
.filter(o -> n % (int) Math.pow(10, o) == 0)
.findFirst()
.orElse(0);
}
Upvotes: 1
Reputation: 7279
Considering you don't have Java9
's takeWhile
method, this can also do the trick:
static final int[] POWERS_OF_10 = { 1000000000, 100000000, 10000000,
1000000, 100000, 10000, 1000, 100, 10 };
static int trailingZeros(int number) {
return Arrays.stream(POWERS_OF_10) // reversed stream of of 10^n
.map(pow -> number % pow) // stream of rests
.reduce(0, (count, rest) -> (rest == 0) ? count + 1 : 0);
}
Upvotes: 1
Reputation: 23788
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 takeWhile
s into one.
Upvotes: 3