代码之家  ›  专栏  ›  技术社区  ›  jcrossley3

使用Ruby和Python中的yield创建列表

  •  3
  • jcrossley3  · 技术社区  · 15 年前

    我正试图想出一种优雅的方法,从一个函数中创建一个列表,这个函数在python和ruby中都会产生值。

    在蟒蛇中:

    def foo(x):
        for i in range(x):
            if bar(i): yield i 
    result = list(foo(100))
    

    露比:

    def foo(x)
      x.times {|i| yield i if bar(i)}
    end
    result = []
    foo(100) {|x| result << x}
    

    尽管我喜欢用两种语言工作,但Ruby版本总是让我有点困扰,它必须先初始化列表,然后再填充它。巨蟒的 yield 结果是简单的迭代,这很好。露比 产量 调用一个块,这也很好,但当我只想填充一个列表时,感觉有点笨拙。

    有更优雅的红宝石风格吗?

    更新 重新编写了该示例,以表明函数生成的值的数量不一定等于x。

    7 回复  |  直到 14 年前
        1
  •  10
  •   horseyguy    14 年前

    因此,对于您的新示例,请尝试以下方法:

    def foo(x)
      (0..x).select { |i| bar(i) }
    end
    

    基本上,除非您正在编写自己的迭代器,否则您不需要 yield 经常用红宝石。如果停止使用Ruby语法编写Python习语,您可能会做得更好。

        2
  •  7
  •   user21714    15 年前

    对于python版本,我将使用如下的生成器表达式:

    (i for i in range(x) if bar(i))
    

    或者对于过滤值的这种特殊情况,更简单地说

    itertools.ifilter(bar,range(x))
    
        3
  •  5
  •   horseyguy    14 年前

    与Python代码(使用Ruby生成器)完全相同的是:

    def foo(x)
        Enumerator.new do |yielder|
            (0..x).each { |v| yielder.yield(v) if bar(v) }
        end
    end
    
    result = Array(foo(100))
    

    在上面的例子中,列表是延迟生成的(就像在Python示例中一样);请参见:

    def bar(v); v % 2 == 0; end
    
    f = foo(100)
    f.next #=> 0
    f.next #=> 2
    
        4
  •  1
  •   Denis Hennessy    15 年前

    我知道这并不完全是你想要的,但是用Ruby来表达你的例子的更优雅的方式是:

    result = Array.new(100) {|x| x*x}
    
        5
  •  1
  •   Wayne    15 年前

    对于stbuton发布的python列表理解版本,请使用 xrange 如果你想要发电机,就用测距代替测距。范围将在内存中创建整个列表。

        6
  •  1
  •   recursive    15 年前

    yield 意思是不同的东西,红宝石和巨蟒。在Ruby中,如果我记得正确的话,您必须指定一个回调块,而Python中的生成器可以传递给持有它们的任何人。

        7
  •  1
  •   horseyguy    14 年前
    def squares(x)
      (0..x).map { |i| i * i }
    end
    

    任何涉及一系列值的东西都最好用一个范围来处理,而不是 times 和数组生成。