gpt4 book ai didi

java - 是否有可能合理地模拟 yield-syntax,或许在 Java 8 的帮助下?

转载 作者:搜寻专家 更新时间:2023-10-30 19:43:05 27 4
gpt4 key购买 nike

我今天正在试验这个问题,来自 Euler Problems:

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.

Find the largest palindrome made from the product of two 3-digit numbers.

我考虑了一下,当然可以用 for 循环来完成,但是我想使用 Java 8,因为它打开了新的选项。

但是首先,我不知道如何生成 IntStream产生这样的元素,所以我最终还是使用了普通的 for 循环:

public class Problem4 extends Problem<Integer> {
private final int digitsCount;

private int min;
private int max;

public Problem4(final int digitsCount) {
this.digitsCount = digitsCount;
}

@Override
public void run() {
List<Integer> list = new ArrayList<>();
min = (int)Math.pow(10, digitsCount - 1);
max = min * 10;

for (int i = min; i < max; i++) {
for (int j = min; j < max; j++) {
int sum = i * j;
if (isPalindrome(sum)) {
list.add(sum);
}
}
}

result = list.stream().mapToInt(i -> i).max().getAsInt();
}

private boolean isPalindrome(final int number) {
String numberString = String.valueOf(number);
String reversed = new StringBuilder(numberString).reverse().toString();
return (numberString.equals(reversed));
}

@Override
public String getName() {
return "Problem 4";
}
}

如您所见,我可能有点懒惰,真的有点 IntStream::max是一个非常好的方法,我认为使用它比自己编写更好。

问题来了,我需要有一个list现在能够以这种方式获得最大值,这意味着我需要存储数据,而我确实不应该这样做。

那么,现在的问题是,是否有可能在 Java 8 中实现它?

for (int i = min; i < max; i++) {
for (int j = min; j < max; j++) {
yield i * j;
}
}

然后用那个方法创建一个 PrimitiveIterator.OfInt (拆箱版本的 Iterator<Integer> ,还是直接创建一个 IntStream
然后用 streamFromYield.filter(this::isPalindrome).max().getAsInt() 得到答案将非常容易实现。

最后,我知道以前有人问过这个问题,但是上次已经很久了,现在 Java 8 很快就会出现,他们在其中添加了一个大概念 Stream<T>和新的语言结构,称为 lambdas。
因此,现在编写此类代码可能与人们为 Java 6 或 7 编写此类代码时截然不同。

最佳答案

好吧,我认为我们已经从“外部”使用 Streams API、使用 flatMap、优化回文查找算法等。请参阅 Boris the Spider 的答案。和 assylias .然而,我们已经回避了最初的问题,即如何使用类似 Python 的 yield 语句来编写生成器函数。 (我认为 OP 的嵌套 - 例如 yield 使用的是 Python。)

使用 flatMap 的问题之一是并行拆分只能发生在最外层的流上。内部流(从 flatMap 返回)按顺序处理。我们可以尝试使内部流也平行,但它们可能会与外部流竞争。我想嵌套拆分可以工作,但我不太有信心。

一种方法是使用 Stream.generate 或(如 assylias 的回答)Stream.iterate 函数。但是,它们会创建无限流,因此必须提供外部 limit 来终止流。

如果我们可以创建一个有限但“扁平化”的流,以便整个值流都可以拆分,那就太好了。不幸的是,创建流并不像 Python 的生成器函数那样方便。不过,它可以毫不费力地完成。下面是一个使用 StreamSupportAbstractSpliterator 类的示例:

class Generator extends Spliterators.AbstractIntSpliterator {
final int min;
final int max;
int i;
int j;

public Generator(int min, int max) {
super((max - min) * (max - min), 0);
this.min = min;
this.max = max;
i = min;
j = min;
}

public boolean tryAdvance(IntConsumer ic) {
if (i == max) {
return false;
}
ic.accept(i * j);
j++;
if (j == max) {
i++;
j = min;
}
return true;
}
}

public static void main(String[] args) {
Generator gen = new Generator(100, 1000);
System.out.println(
StreamSupport.intStream(gen, false)
.filter(i -> isPalindrome(i))
.max()
.getAsInt());
}

不是让迭代变量在堆栈上(就像在嵌套 for 和 yield 方法中那样)我们必须使它们成为对象的字段并让 tryAdvance 递增它们直到迭代完成完全的。现在,这是拆分器的最简单形式,不一定能很好地并行化。通过额外的工作,可以实现 trySplit 方法来进行更好的拆分,从而实现更好的并行性。

forEachRemaining 方法可以被覆盖,它看起来几乎像 nested-for-loop-with-yield 示例,调用 IntConsumer 而不是 产量。不幸的是,tryAdvance 是抽象的,因此必须实现,因此仍然有必要将迭代变量作为对象的字段。

关于java - 是否有可能合理地模拟 yield-syntax,或许在 Java 8 的帮助下?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21972572/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com