1

有关于 D 中的函数式编程的文章和演示文稿(例如http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321)。我以前从未使用过 D,但我有兴趣尝试一下。有没有办法在 D 中编写类似于此 Python 表达式的代码:

max(x*y for x in range(N) for y in range(x, N) if str(x*y) == str(x*y)[::-1])

是否有用于生成器或列表(数组)推导的 D 构造?

4

2 回答 2

4

这是一种可能的解决方案,不是特别漂亮:

iota(1,N)
    .map!(x =>
        iota(x,N)
        .map!(y => tuple(x,y)))
    .joiner
    .map!(xy => xy[0]*xy[1])
    .filter!(xy => equal(to!string(xy), to!string(xy).retro))
    .reduce!max;

所以这实际上是创建一个从 1 到 N 的范围,并将每个元素映射到具有 x,y 值的元组范围。这为您提供了一个嵌套范围([[(1,1),(1,2)],[(2,2)]],N = 2)。

然后我们加入这个范围以获得一个元组范围([(1,1),(1,2),(2,2)],N = 2)。

接下来我们映射到 x*y(D 的映射由于某种原因不允许解包元组,所以我们需要使用索引)。

倒数第二个我们过滤掉非回文,最后将范围缩小到最大元素。

于 2013-07-07T10:14:52.783 回答
3

简单的答案,不,D 没有生成器或列表推导(AFAIK)。但是,您可以使用 InputRange 创建生成器。对于该解决方案,请参阅此相关问题:D 编程语言中的“收益回报”等价物是什么?

但是,您的代码没有使用生成器,因此您的代码可以翻译为:

import std.algorithm : max, reduce, retro, equal;
import std.conv : to;
immutable N = 13;

void main() {
    int[] keep;
    foreach(x; 0 .. N) {
        foreach(y; x .. N) {
            auto val = x*y;
            auto s = to!string(val);
            if (equal(s, s.retro)) // reverse doesn't work on immutable Ranges
                keep ~= val; // don't use ~ if N gets large, use appender instead
        }
    }
    reduce!max(keep); // returns 121 (11*11)
}

对我来说,这比您的列表理解更具可读性,因为列表理解已经变得非常大。

那里可能有更好的解决方案,但这就是我实施它的方式。额外的好处是您可以看到 std.algorithm 的所有荣耀。

但是,对于这段特定的代码,我不会使用数组来节省内存,而是只存储最佳值以节省内存。像这样的东西:

import std.algorithm : retro, equal;
import std.conv : to;
immutable N = 13;

void main() {
    int best = 0;
    foreach(x; 0 .. N) {
        foreach(y; x .. N) {
            auto val = x*y;
            auto s = to!string(val);
            if (equal(s, s.retro))
                best = val;
        }
    }
}
于 2013-07-07T10:03:43.540 回答