2012-07-05 175 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