【问题标题】:Is there a way to write code in D similar to this Python expression?有没有办法在 D 中编写类似于这个 Python 表达式的代码?
【发布时间】:2013-07-07 09:17:39
【问题描述】:

有关于 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 构造?

【问题讨论】:

    标签: functional-programming generator d list-comprehension


    【解决方案1】:

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

    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)] for N = 2)。

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

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

    【讨论】:

    • 你可以颠倒它们,使它看起来更像python表达式:但会有很多括号要关闭
    • @ratchetfreak 我更喜欢“管道”风格,遗憾的是 Python 中缺少这种风格。不需要这个)))))))))))))))))
    【解决方案2】:

    简单的答案,不,D 没有生成器或列表推导(AFAIK)。但是,您可以使用 InputRange 创建生成器。对于该解决方案,请参阅此相关问题:What is a "yield return" equivalent in the D programming language?

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

    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;
            }
        }
    }
    

    【讨论】:

    • 但是,您的代码没有使用生成器
    • @PaulJurczak - 我不知道其中的区别,所以我坚持纠正。更详细的 InputRange 选项(来自链接的问题)将是您的 Python 代码的更准确的翻译。如果我有时间,我会考虑提供它作为一个选项,因为这是解决问题的更通用的方法,但嵌套循环使其实现起来更有趣。
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2012-07-19
    • 2021-10-18
    • 2019-04-03
    • 2010-11-25
    • 2017-01-04
    • 2013-04-24
    • 1970-01-01
    相关资源
    最近更新 更多