使用 Java 8 Streams 将迭代方法转换为函数式方法
Convert iterative method to functional with Java 8 Streams
我这里有这个算法,
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;
}
这给了我损失精度为 e 的 n 的立方根。我需要做同样的事情,但使用 Java 8 个流。 Math2 来自私人 git 代表。您可以使用 Math.pow 代替;它也会起作用。如何使用 Streams 执行相同的算法?
Java Stream API 有从 Java 9 开始的方法 Stream::iterate
,因此可以实现代表迭代 steps/states 的 class如下:
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;
}
}
那么基于流的解决方案如下所示:
- 用
start
、end
、n
定义初始种子
- 使用
Stream::iterate
和 hasNext
谓词创建一个 有限 流
2a) 或使用不带 hasNext
但带有 Stream::takeWhile
操作的旧 Stream::iterate
有条件地限制流 - 自 Java 9 起也可用
- 使用
Stream::reduce
to 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 static 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
我这里有这个算法,
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;
}
这给了我损失精度为 e 的 n 的立方根。我需要做同样的事情,但使用 Java 8 个流。 Math2 来自私人 git 代表。您可以使用 Math.pow 代替;它也会起作用。如何使用 Streams 执行相同的算法?
Java Stream API 有从 Java 9 开始的方法 Stream::iterate
,因此可以实现代表迭代 steps/states 的 class如下:
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;
}
}
那么基于流的解决方案如下所示:
- 用
start
、end
、n
定义初始种子
- 使用
Stream::iterate
和hasNext
谓词创建一个 有限 流 2a) 或使用不带hasNext
但带有Stream::takeWhile
操作的旧Stream::iterate
有条件地限制流 - 自 Java 9 起也可用
- 使用
Stream::reduce
to 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 static 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