【问题标题】:Convert iterative method to functional with Java 8 Streams使用 Java 8 Streams 将迭代方法转换为函数式
【发布时间】:2021-10-10 16:03:19
【问题描述】:

我这里有这个算法,

    while ((start + end) / 2 != 0) {
        Double mid = (start + end) / 2;
        if (Math2.pow(mid, 3) < n) {
            start = mid;
        } else if (Math.abs(n - Math2.pow(mid, 3)) > Math2.pow(e, 3)) {
            end = mid;
        } else if (Math.abs(n - Math2.pow(mid, 3)) < Math2.pow(e, 3)) {
            return mid;
        }
    }
    return 0.0;

}

这给了我 n 的三次根,损失精度为 e。我需要做同样的事情,但使用 Java 8 Streams。 Math2 来自私人 git 代表。您可以改用 Math.pow;它也会起作用。如何使用 Streams 执行相同的算法?

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    Java Stream API 具有从 Java 9 开始的方法 Stream::iterate,因此表示迭代步骤/状态的类可以实现如下:

    class CubeSolver {
        static final double EPS = 1E-06;
            
        private double start, end, n, mid;
    
        public CubeSolver(double s, double e, double n) {
            this.start = s;
            this.end = e;
            this.n = n;
            this.mid = (start + end) / 2;
        }
    
        // UnaryOperator<CubeSolver> for iteration
        public CubeSolver next() {
            if (done()) {
                return this;
            }
            if (Math.pow(mid, 3) < n) {
                start = mid;
            } else if (Math.abs(n - Math.pow(mid, 3)) > EPS) {
                end = mid;
            }
            return new CubeSolver(start, end, n);
        }
        
        // define end of calculation
        public boolean done() {
            return mid == 0 || Math.abs(n - Math.pow(mid, 3)) < EPS;
        }
        
        @Override
        public String toString() {
            return "root = " + mid;
        }
    }
    

    那么基于流的解决方案是这样的:

    1. 使用startendn 定义初始种子
    2. 使用Stream::iteratehasNext 谓词来创建一个有限 流 2a) 或使用较旧的 Stream::iterate 而不使用 hasNext 但使用 Stream::takeWhile 操作来有条件地限制流 - 自 Java 9 起也可用
    3. 使用Stream::reduceto get the last element of the stream
    CubeSolver seed = new CubeSolver(1.8, 2.8, 8);
    CubeSolver solution = Stream
        .iterate(seed, cs -> !cs.done(), CubeSolver::next)
        .reduce((first, last) -> last) // Optional<CubeSolver>
        .orElse(null);
        
    System.out.println(solution); 
    

    输出:

    root = 2.0000002861022947
    

    在 Java 11 中添加了静态 Predicate::not,因此使用 takeWhile 的 2a 解决方案可能如下所示:

    CubeSolver seed = new CubeSolver(0, 7, 125);
    CubeSolver solution = Stream
        .iterate(seed, CubeSolver::next)
        .takeWhile(Predicate.not(CubeSolver::done))
        .reduce((first, last) -> last) // Optional<CubeSolver>
        .orElse(null);
        
    System.out.println(solution); 
    

    输出(对于 EPS = 1E-12):

    root = 4.999999999999957
    

    【讨论】:

      猜你喜欢
      • 2016-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 2016-09-23
      • 2018-03-26
      相关资源
      最近更新 更多