如何使用 Java 8 Stream/Lambda 计算整数中尾随零的数量?

问题描述 投票:0回答:4

如何使用 Java 8 Stream/Lambda 计算整数中尾随零的数量?

基本上逻辑应该是:保持整数除以

10
,只要余数为
0
(商将提供给下一个除法)并计算出现次数。

例如

12300 % 10 == 0
true

1230 % 10 == 0
true

123 % 10 == 0
false

答案:

2

注意:我不喜欢在这里涉及字符串:-)

java algorithm lambda java-8 java-stream
4个回答
3
投票

如果这是一个纯粹假设的问题,这里有一个纯粹假设的答案,告诉你如何做到这一点:

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
合并为一个。


1
投票

考虑到你没有

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);
}

1
投票

还有另一种方法:-

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);
}

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.