如何使用 Java 8 Stream/Lambda 计算整数中尾随零的数量?
基本上逻辑应该是:保持整数除以
10
,只要余数为0
(商将提供给下一个除法)并计算出现次数。
例如
12300 % 10 == 0
true
1230 % 10 == 0
true
123 % 10 == 0
false
答案:
2
注意:我不喜欢在这里涉及字符串:-)
如果这是一个纯粹假设的问题,这里有一个纯粹假设的答案,告诉你如何做到这一点:
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();
}
它使用了一个辅助函数
takeWhile
,该函数在 Java 9 中可用,但在 Java 8 中不可用,因此必须像这样进行模拟:
// 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);
}
这个想法是
IntStream.iterate(value, v1 -> v1 / 10).takeWhile(v -> v > 0)
应该在末尾生成一串切割数字,然后您可以应用
takeWhile(v -> v % 10 == 0).count()
来计算零的数量,最后您可以将这两个 takeWhile
合并为一个。
考虑到你没有
Java9
的takeWhile
方法,这也可以解决问题:
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);
}
还有另一种方法:-
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 的编辑:
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);
}
您只需使用
IntStream.iterate
即可使用它。
v%10
使用余数运算符隔离 v
的最后一位数字v/10
有效地删除了 v
使用该值作为种子。
0
,请将其放入流中int[] 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);
}