【问题标题】:How to apply a Stream reduction (count) to a IntStream and change the return type to "int"如何将流减少(计数)应用于 IntStream 并将返回类型更改为“int”
【发布时间】:2019-02-11 16:18:56
【问题描述】:

这段代码无法编译:

public int trailingZeroes(int n) {
    return IntStream.rangeClosed(1,n)
            .filter(e -> (e  % 5) == 0)
            .count();
}

我注意到IntStream 的返回类型存在这种差异 方法:

int sum()long count()

在尝试从上面的计数操作中返回 int 类型时,

  • 我已经明白为什么 count() 返回一个 long 但为什么有 sum() 返回比 count() 更窄的返回类型?

  • 在我的
    trailingZeroes 方法中实现我想要实现的目标的最佳方法是什么?

【问题讨论】:

  • 这个方法不就是在做(int) n / 5吗?
  • @jbx 不,不一定。它目前将计算所有小于 N 且可被 5 整除的数字。除此之外:这似乎更像是一个数学问题,用于计算数字中尾随的零的数量。但是,如果我没记错的话,那曾经是(n/5 + n/25 + n/125 ....)。只有 OP 可以分享详细信息。
  • @nullpointer OP 所做的只是取可被 5 整除且没有余数的范围内的数字,因此将其除以 5 并删除小数部分将得到相同的结果。范围是封闭的,所以数字小于或等于 N。(如果不是,它只是(int) (n - 1) / 5)。它从 1 开始(甚至可以从 5 开始,结果是一样的)。
  • @jbx 是的,我明白你现在的意思了,我真的认为该方法的名称及其作用在这里具有误导性。在做出的回答中提出了更好的实施方案。
  • @nullpointer 是的,看到了。也启发了我一个递归的:)

标签: java java-stream reduction


【解决方案1】:

sum 方法返回一个 int,因为两个 int 的和是一个 int。

count 的 Javadoc 说它等同于 mapToLong(e -> 1L).sum()。您可以使用它来进行自己的计数,返回 int,如下所示:

return IntStream.rangeClosed(1,n)
        .filter(e -> (e  % 5) == 0)
        .map(e -> 1)
        .sum();

或者,因为您实际上知道您的答案无论如何都适合int,所以只需转换它:

return (int) IntStream.rangeClosed(1,n)
        .filter(e -> (e  % 5) == 0)
        .count();

【讨论】:

    【解决方案2】:

    我已经明白为什么 count() 返回一个 long 但为什么 sum() 返回一个比 count() 窄的返回类型?

    sum() 返回流中项目的总和,因此返回的类型与流的类型匹配。 LongStream.sum() 返回long

    count() 与来自流的对象的类型没有直接关系,并且为了符合他们选择的其余Streamlong,表示最大大小的类型。 count() 方法实际上是在Stream 接口级别定义的,然后由BaseStream 扩展,随后由IntStream 扩展,因此必须保留方法签名的契约。 (理想情况下,count() 应该返回 unsigned,但 Java 不支持 unsigned。)

    什么是实现我想要做的事情的最佳方式 trailingZeroes 方法?

    不清楚您要达到的目标。但我认为这并没有什么特别的问题。

    如果您希望它返回int,请在返回之前转换该值。我假设您知道结果将始终安全地放入int(结果将始终小于n,即int),除非您想将方法的返回类型更改为long .

    另一方面,无法理解这种方法应该做什么。你本来可以这样做的:

    public int trailingZeroes(int n) {
      return n / 5;
    }
    

    如果您正在寻找一种数学方法来确定整数中有多少个尾随0s,那就不同了。您已经有了建议的答案,因此冒昧地提出一个递归解决方案来取乐:

    public int trailingZeroes(int n) {
       return (n % 10 != 0) 
            ? 0 
            : 1 + trailingZeroes(n / 10);
    }
    

    【讨论】:

      【解决方案3】:

      count() 返回一个 long 但为什么 sum() 返回一个较窄的返回 type 比 count() 多?

      从 Javadocs 来看,IntStream.count 恰好是缩减的一个特例

      return mapToLong(e -> 1L).sum();
      

      这就是它返回long 的原因。进一步的IntStream.sum 又是一个特殊的缩减,它在内部使用Integer.sum

      return reduce(0, Integer::sum) // signature of sum being 'int sum(int a, int b)'
      

      这就是它返回int的原因。

      什么是实现我想要做的事情的最佳方式 trailingZeroes 方法?

      对其他解决方案进行了轻微优化,您可以只使用map

      public int trailingZeroes(int n) {
          return IntStream.rangeClosed(1, n)
              .map(e -> (e % 5) == 0 ? 1 : 0)
              .sum();
      }
      

      从方法名称推断,您在实现中应该寻找的应该是:

      public int trailingZeroes(int n) {
          int count = 0;
          while (n % 10 == 0) {
              count++;
              n = n / 10;
          }
          return count;
      }
      

      以 Java-9 语法表示时应如下所示:

      public int trailingZeroes(int n) {
          return (int) IntStream.iterate(n, i -> i % 10 == 0, i -> i / 10).count();
      }
      

      【讨论】:

      • iterate()一起酷用Java 9解决方案
      【解决方案4】:

      sum() 返回此流中元素的总和,由于您使用IntStreamsum() 返回 int 类型。注意:LongStreamsum() 方法将返回 long 类型。

      要获得int,您可以使用强制转换:

      return (int)IntStream.rangeClosed(1,n)
                  .filter(e -> (e  % 5) == 0)
                  .count();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-04
        • 1970-01-01
        • 2022-10-14
        • 1970-01-01
        • 2023-04-04
        • 1970-01-01
        相关资源
        最近更新 更多