2012-04-18 53 views
3

我正在尋找一種與Ruby中的Python的itertools.product具有相同效果的方法。看看下面的Python代碼:Ruby中Python的itertools.product的等價物是什麼?

from itertools import product 

chars = [] 
for i in range(97,123): 
    chars.append(chr(i)) 

for a in range(1,3): 
    for i in product(chars,repeat=a): 
     s = ''.join(i) 
     print s 

輸出是這樣的:

a, b, c... x, y, z, aa, ab, ac... ax, ay, az, ba, bb, bc.. etc. 

我試着翻譯成紅寶石:

(1..2).each do |n| 
    ('a'..'z').to_a.combination(n).each do |c| 
    s = c.join 
    puts s 
    end 
end 

但輸出是不一樣的。單字符的那些做工精細(AZ),但是當它進入兩個字符的,如我所料不工作:

ab, ac, ad.. ax, ay, az, bc, bd, be 

它不產生aababb - 因此它出現它產生的所有組合沒有重複字符或東西?

那麼我應該用什麼方法來生成全部itertools.product這樣的組合在Python中呢?

+0

'Array#product'和'itertools.product'的主要區別在於Ruby的方法不是函數。這通常是不方便的。 – tokland 2012-04-18 15:54:04

回答

3

我會寫的一個(簡化爲3個元素,紅寶石1。要求9):

xs = ["a", "b", "c"] 
strings = 1.upto(xs.size).flat_map do |n| 
    xs.repeated_permutation(n).map(&:join) 
end 
#=> ["a", "b", "c", "aa", "ab", "ac", ..., "cca", "ccb", "ccc"] 

懶惰的解決方案:你可以把它與each s,而不是map小號容易寫,但讓我們檢查 「懶」 在Ruby 2.0:

xs = ("a".."z").to_a 
strings = 1.upto(xs.size).lazy.flat_map do |n| 
    xs.repeated_permutation(n).lazy.map(&:join) 
end 
+0

很好用,但是有沒有什麼辦法可以讓它成爲一個發電機? - 用6個字符的a-z字符串佔用我所有的RAM! – 2012-04-18 17:25:22

+0

對於懶惰的解決方案:1)使用每個而不是地圖。 2)品嚐Ruby 2.0中的懶惰模式:http://bugs.ruby-lang.org/attachments/1803/lazy.rb。在flat_map和map之前添加lazy,然後添加每個表達式。 – tokland 2012-04-18 17:31:33

+0

感謝 - [完成它](http://stackoverflow.com/a/10214763/840973)與循環。 – 2012-04-18 17:33:56

1

您有Array#product這就像itertools.product

+0

我試過,但無法讓它工作 - 你能給出一個例子,給出與我的Python代碼相同的輸出嗎? – 2012-04-18 14:36:37

+0

在Ruby中使用itertools.product docs(_product('ABCD','xy')_)中給出的示例可能類似於_%w {ABCD} .product(%w {xy})。map(&:join )_ – 2012-04-18 14:43:00

+0

我的意思是使用重複 - 就像在我的Python示例中一樣,'product(chars,repeat = a)'(a是1,然後是2) - 如果要生成每個5個字符組合,該怎麼辦? - 在Python中,你會做'product(chars,repeat = 5)' - 你怎麼能在Ruby中做到這一點? – 2012-04-18 14:49:48

2

魔術(雖然不是很漂亮):

a = ('a'..'z').to_a 
result = (0..2).map { |n| 
    a.product(*n.times.inject([]) { |s,x| s << a }) }.map { |x| x.map(&:join) } 
} 

puts result 

說明:爲了爲蟒蛇product工作,你需要重複陣列n-1倍,在product參數。

所以product('abc', repeat=n)是紅寶石一樣的:

a = ['a','b','c'] 
a.product()  # n = 1 
a.product(a) # n = 2 
a.product(a, a) # n = 3 

那討厭的inject確實在上面的代碼是什麼。它自動構建這樣一個「參數數組」。雖然它不是非常高效的代碼,所以不要試圖用它來構建大型「產品」。

+0

謝謝! - 所以它看起來好像沒有與Python的'repeat'參數相當的內建函數呢? – 2012-04-18 15:23:55

+0

@AlexCoplan不,沒有直接的等價物,我至少可以在std庫中找到。 – Casper 2012-04-18 15:27:38

+0

@AlexCoplan然而對於'a.product(* [a] * n)',你會變得非常接近。在Python中,'n'等同於'repeat = n'。 – Casper 2012-04-18 15:40:59

1

我寫完後,我注意到卡斯帕的解決方案基本上是一樣的。有些人可能會覺得這一個更具可讀性,所以我離開它..

arr = ['a', 'b', 'c'] 

p (0..2).inject([]) { |acc, a| 
    acc + arr.product(*[arr]*a).map(&:join) 
} 

=> ["a", "b", "c", "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc", "aaa", "aab", "aac", "aba", "abb", "abc", "aca", "acb", "acc", "baa", "bab", "bac", "bba", "bbb", "bbc", "bca", "bcb", "bcc", "caa", "cab", "cac", "cba", "cbb", "cbc", "cca", "ccb", "ccc"] 

主要「陷阱」將是

  • *[arr]*a,其中首先創建的aarr秒的數組,然後潑濺入a參數product方法。
  • map(&:join),這是map{|e| e.join}
  • inject的速記(又名 「減少」,由 「映射簡化」 成名)中,FP支柱
+0

不錯的一個。比我的好多了:) – Casper 2012-04-18 15:23:42

1

在Ruby中,數組#產品導致Cathesian產品。添加原始數組會產生相同的結果。

ar = (?a..?z).to_a 
ar + ar.product(ar).map(&:join) 
0

隨着tokland的幫助下,我知道了:

(1..2).each do |n| 
    ('a'..'z').to_a.repeated_permutation(n).each do |a| 
    s = a.join 
    puts s 
    end 
end 

而且它的懶惰,所以當你使用它來生成更長的字符串不生豬RAM。

相關問題