2012-10-06 205 views
1

我正在用Ruby做SaaS课程。在练习中,我被要求通过使用迭代器,块和屈服来计算两个序列的笛卡尔乘积。Ruby的例子说明?

我结束了这个,纯粹的猜测和错误,它似乎工作。但我不确定如何。我似乎了解基本块和产量使用情况,但是这?一点也不。

class CartProd 
    include Enumerable 
    def initialize(a,b) 
     @a = a 
     @b = b 
    end 
    def each 
     @a.each{|ae| 
       @b.each{|be| 
         yield [ae,be] 
       } 
     } 
    end 
end 

对像我这样的noob有些解释吗?

(PS:我改变所需的类名CartProd所以人在做的过程中不能找到这么容易Google上搜寻它的响应)

+0

备注:类变量@@ a和@@ b是有害的(尝试使用两个实例)。它们应该被@a和@b取代。 – steenslag

+0

谢谢,我会纠正它。所以@@定义了类变量和@实例变量。 –

+0

顺便说一句,'包含Enumerable'行是不必要的。 – manzoid

回答

0

究竟你这里不明白吗?你已经做了一个迭代器,它产生了所有可能的元素对。如果你通过CartProd#each一个块,它将被执行a.length*b.length次。这就像有两个不同的for循环以任何其他编程语言折叠成另一个循环。

+1

也许我不明白什么产量正在那里做 –

+0

它只是执行一个块,如果你的方法调用有一个。您在yield调用中指定的任何参数都将传递给block。 – Anton

+0

'yield [ae,be]'通知调用代码返回值是'[ae,be]'。详细阅读[使用可枚举模块](http://ruby.about.com/od/advancedruby/ss/Using-The-Enumerable-Module.htm)应该可以帮助您了解该示例的工作方式。 –

0

yield只是将控制权交给(产生)控制到已作为方法调用的一部分传入的代码块。 yield关键字后的值作为参数传递到块中。一旦块完成执行后,它就回传控制权。

所以,在你的榜样,你可以调用#each这样的:

CartProd.new([1, 2], [3, 4]).each do |pair| 
    # control is yielded to this block 
    p pair 
    # control is returned at end of block 
end 

这将输出每对值。

7

让我们一步一步来构建。我们将通过从类上下文中取出来简化一些事情。

对于这个例子,直觉上认为迭代器是一个更强大的替代传统的for循环。

所以首先这里有一个for循环版本:

seq1 = (0..2) 
seq2 = (0..2) 
for x in seq1 
    for y in seq2 
    p [x,y] # shorthand for puts [x, y].inspect 
    end 
end 

现在让我们来替换成更Ruby的成语迭代式的,明确供应区块执行命令(即do...end块):

seq1.each do |x| 
    seq2.each do |y| 
    p [x,y] 
    end 
end 

到目前为止,这么好,你已经打印出你的笛卡尔产品。现在您的任务也会要求您使用yieldyield的要点是“产生执行”,即临时将控制传递给另一个代码块(可选地传递一个或多个参数)。

所以,虽然它不是这个玩具例子实际上必要的,而不是直接打印像上面的值,可以yield的价值,并让来电者提供接受该值并打印出来,而不是块。

这可能看起来像这样:

def prod(seq1, seq2) 
    seq1.each do |x| 
     seq2.each do |y| 
     yield [x,y] 
     end 
    end 
    end 

可赎回这样的:

prod (1..2), (1..2) do |prod| p prod end 

yield提供用于内循环的每个运行中的产品,并且得到的值由块印刷由主叫方提供。

+0

只需添加:一个简单的写法是'yield seq1.product(seq2)' – Anorov