【问题标题】:How to count the number of trailing zeroes in an integer using Java 8 Stream/Lambda?如何使用 Java 8 Stream/Lambda 计算整数中尾随零的数量?
【发布时间】:2019-01-29 17:33:12
【问题描述】:

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

基本上逻辑应该是:保持整数除以10,只要余数是0(商将提供给下一个除法)并计算出现次数。

例如

12300 % 10 == 0true

1230 % 10 == 0true

123 % 10 == 0false

回答:2

注意:我不想在这里涉及 String :-)

【问题讨论】:

  • Integer 类中有一个方法...
  • @Eugene,我相信 Integer.numberOfTrailingZeros 方法适用于二进制级别,而不是 OP 要求的十进制。还是您的意思是其他方法?
  • @Saikat,我相信 Java8 流不是为这种使用场景而设计的。你有什么特别的理由使用Stream 而不是一个简单的for 循环来实现它吗?
  • 我只是想知道这是否可能 :) @SergGr Number.numberOfTrailingZeros 是一个很好的启示;)我需要做的就是将其转换为十进制(正如您正确指出的那样)
  • 我的意思是hereStream 版本,但它涉及到String 的转换

标签: java algorithm lambda java-8 java-stream


【解决方案1】:

如果这是一个纯粹假设的问题,那么这里是一个关于如何做到这一点的纯粹假设的答案:

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()来计算零的数量,最后你可以将这两个takeWhiles合并为一个。

【讨论】:

    【解决方案2】:

    考虑到您没有Java9takeWhile 方法,这也可以解决问题:

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

    【讨论】:

      【解决方案3】:

      这是另一种方式:-

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

      【讨论】:

      • 当您将.map(o -> (int) Math.pow(10, o)) .filter(o -> n % o == 0) 替换为单个.filter(o -> n % (int) Math.pow(10, o) == 0) 步骤时,最后不需要.map(i -> (int) Math.log10(i))。这反过来又消除了对.boxed() 的需要。
      猜你喜欢
      • 2018-11-06
      • 1970-01-01
      • 2014-01-11
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 1970-01-01
      相关资源
      最近更新 更多