2012-07-05 174 views
6
class CartesianProduct 
include Enumerable 
# your code here 
end 
#Examples of use 
c = CartesianProduct.new([:a,:b], [4,5]) 
c.each { |elt| puts elt.inspect } 
# [:a, 4] 
# [:a, 5] 
# [:b, 4] 
# [:b, 5] 
c = CartesianProduct.new([:a,:b], []) 
c.each { |elt| puts elt.inspect } 
# (nothing printed since Cartesian product 
# of anything with an empty collection is empty) 

我是新来的红宝石。我了解如何定义Cartesian Product的实例方法,但我不知道这一点。我应该如何构造类对象来满足要求。笛卡尔积Ruby

+0

你能否澄清你所要求的?你应该如何构建什么?你是否试图创建一个名为'CartesianProduct'的类来完成所显示的内容? – denniss 2012-07-05 20:29:14

+0

是的,它需要一个类的方法。我知道如何构造一个实例方法来返回一个值,但我不知道如何构造类方法来修改类对象的值。 – ZhijieWang 2012-07-05 20:36:04

+0

这是功课吗?如果是这样,那没关系,人们会试着将你推向正确的方向。 – steenslag 2012-07-05 20:57:39

回答

6

我不会用为一类,但保持了问题的结构,我会写:

class CartesianProduct 
    include Enumerable 

    def initialize(xs, ys) 
    @xs = xs 
    @ys = ys 
    end 

    def each 
    return to_enum unless block_given? 
    @xs.each do |x| 
     @ys.each { |y| yield [x, y] } 
    end 
    end 
end 

相反,我会简单的写xs.product(ys)或建立自己的Array#lazy_product如果懒惰是重要的(见ticket)。

+0

虽然有没有必要使用懒惰?直接出来'each'和'yield'会更简单更快 – 2012-07-05 21:30:01

+0

好吧,你说得对,虽然老实说我最喜欢懒惰的版本,但它是一种更实用的方法(并且返回一个枚举器,如果没有块使用,就像一个标准'each')。 – tokland 2012-07-05 21:46:18

+0

确实,你应该从典型的'return to_enum开始,除非block_given?' – 2012-07-06 05:04:53

22

我建议使用Array#product

[:a, :b].product [4,5] 

这将产生你想要的输出。

irb(main):001:0> [:a, :b].product [4,5] 
=> [[:a, 4], [:a, 5], [:b, 4], [:b, 5]] 
irb(main):002:0> 

如果你想要一个懒惰的排列生成器,我以前写过类似的东西。但是我警告你,如果你有大量的排列来计算它可能需要一段时间。你应该能够从this file的前40-45行获得你需要的东西(无论如何这个文件是一个实验)。

诀窍在于使用Ruby 1.9.2构建枚举器来处理数组的数组。因此,您首先创建一个循环访问数组的枚举数,并在您的数组数组中循环第一个输出集,并在第二次输入时结束循环。这是我能弄清楚如何终止这样一个循环的唯一方法。

def infinite_iterator(array) 
    Enumerator.new do |result| 
    loop do 
     array.cycle { |item| result << item } 
    end 
    end 
end 

def cartesian_iterator(data) 
    Enumerator.new do |result| 
    first = data.map { |p| p.next } 
    result << first 

    i = 1 
    parts = first.dup 
    loop do 
     parts[2-i] = data[2-i].next 
     break if parts == first 

     result << parts.join 
     i = ((i + 1) % parts.size) 
    end 
    end 
end 

array = [ infinite_iterator([:a,:b]), infinite_iterator([4,5]) ] 
generator = cartesian_iterator(array) 

generator.each { |a| p a } 
+0

两个空阵列呢?结果会是什么? – ZhijieWang 2012-07-05 20:48:00

+1

@ user1505108你以前试过IRB吗?结果是'[]'。 – 2012-07-05 20:52:15

6

你需要在你的类,为产品的每一个组合叫yield定义一个each方法。

您可以使用Array#product,但它返回一个数组,所以它不是懒惰的。

Ruby 2.0中有一个proposal for Array.product可以做到这一点。

+0

谢谢,解决了问题 – ZhijieWang 2012-07-05 20:49:35

+0

@ user1505108然后,您应该标记此答案(v符号)。 – steenslag 2012-07-05 21:30:48