Python有一个很好的功能:
print([j**2 for j in [2, 3, 4, 5]]) # => [4, 9, 16, 25]
在Ruby中,它甚至更简单:
puts [2, 3, 4, 5].map{|j| j**2}
但是如果它是关于嵌套循环的Python看起来更方便。
在Python中我们可以这样做:
digits = [1, 2, 3]
chars = ['a', 'b', 'c']
print([str(d)+ch for d in digits for ch in chars if d >= 2 if ch == 'a'])
# => ['2a', '3a']
Ruby中的等价物是:
digits = [1, 2, 3]
chars = ['a', 'b', 'c']
list = []
digits.each do |d|
chars.each do |ch|
list.push d.to_s << ch if d >= 2 && ch == 'a'
end
end
puts list
Ruby有类似的东西吗?
答案 0 :(得分:11)
Ruby中常见的方法是正确组合Enumerable和Array方法来实现相同的目标:
digits.product(chars).select{ |d, ch| d >= 2 && ch == 'a' }.map(&:join)
这比列表理解只有4个左右的字符,而且就像表达一样(当然,恕我直言,但由于列表推导只是列表monad的一个特殊应用,人们可能会认为可能有可能充分重建使用Ruby的集合方法),但不需要任何特殊的语法。
答案 1 :(得分:2)
如你所知,Ruby没有列表推导的语法糖,所以你越接近就能以富有想象力的方式使用块。人们提出了不同的想法,看看lazylist和verstehen方法,都支持嵌套的理解条件:
require 'lazylist'
list { [x, y] }.where(:x => [1, 2], :y => [3, 4]) { x+y>4 }.to_a
#=> [[1, 4], [2, 3], [2, 4]]
require 'verstehen'
list { [x, y] }.for(:x).in { [1, 2] }.for(:y).in { [3, 4] }.if { x+y>4 }.comprehend
#=> [[1, 4], [2, 3], [2, 4]]
当然,这不是您所谓的惯用Ruby,因此使用典型的product
+ select
+ map
方法通常会更安全。
答案 2 :(得分:1)
正如上面的RBK所建议的那样,List comprehension in Ruby提供了大量不同的方法来处理Ruby中的列表推导。
它们都没有明确描述嵌套循环,但至少其中一些可以很容易地嵌套。
例如,Robert Gamble接受的答案建议添加一个Array#comprehend方法。
class Array
def comprehend(&block)
return self if block.nil?
self.collect(&block).compact
end
end
完成后,您可以将代码编写为:
digits.comprehend{|d| chars.comprehend{|ch| d.to_s+ch if ch =='a'} if d>=2}
与Python代码比较:
[str(d)+ch for d in digits for ch in chars if d >= 2 if ch == 'a']
差异很小:
当然,Python的真正优势在于,如果您决定要懒惰地评估列表,可以通过删除括号(或根据上下文将它们转换为括号)将您的理解转换为生成器表达式。但即使在那里,你也可以创建一个Array#lazycomprehend等等。