2012-04-18 21 views
3

RubyでPythonのitertools.productと同じ効果を持つメソッドを探しています。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 

このようなものを出力します:次のPythonコード乗り

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

しかし、出力が同じではありません。

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

を私は、Rubyの中にそれを翻訳してみました。 1文字のものは(AZ)正常に動作しますが、それは2文字のものになったとき、私は予想通り、それは動作しません:それはaabaまたはbbを生成していない

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

- それそれは文字や何かを繰り返さずにすべての組み合わせを生成しているようですか?

すべてのような組み合わせを生成するにはどのような方法を使用する必要がありますか?itertools.productのようなものはPythonで動作しますか?

+0

'Array#product'と' itertools.product'の主な違いは、Rubyが関数ではなくメソッドであることです。それは通常不便です。 – tokland

答えて

3

Iは3つの要素のために簡略化(記述し、 Ruby 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でそれを書くことができmap Sの代わりにね、しかしのはルビー2.0から "怠け者" チェックしてみましょう:Rubyで

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が使用されます! –

+0

怠惰な解決法の場合:1)マップの代わりにそれぞれを使用します。 2)Ruby 2.0の怠惰なパターンを味わう:http://bugs.ruby-lang.org/attachments/1803/lazy.rb。 flat_mapとmapの前にlazyを追加し、それぞれの式を追加します。 – tokland

+0

ありがとう - [done it](http://stackoverflow.com/a/10214763/840973)ループ。 –

1

あなたはitertools.productのようなArray#productを持っています。

+0

私はそれを試みましたが、動作させることができませんでした - 私のPythonコードと同じ出力を与える例を与えることができますか? –

+0

Rubyでitertools.product docs(_product( 'ABCD'、 'xy')_)の例を使用すると、%w {ABCD} .product(%w {xy})のようになります。 )_ –

+0

私のPythonの例では、 'product(chars、repeat = a)'(aは1、次に2)のように繰り返しを使うことを意味します。 - Pythonでは、 'product(chars、repeat = 5)'を実行するでしょう - Rubyではどうしたらいいですか? –

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 

説明:pythonのように動作するためにproductあなたはproduct引数に配列をn-1回繰り返す必要があります。

だからproduct('abc', repeat=n)はとルビーでも同じです:

厄介な injectは、上記のコードで何をするかだ
a = ['a','b','c'] 
a.product()  # n = 1 
a.product(a) # n = 2 
a.product(a, a) # n = 3 

。このような「引数配列」を自動的に構築します。しかし、非常に効率的なコードではありませんので、大きな "製品"を構築しようとしないでください。

+0

ありがとう! - それで、Pythonの 'repeat'引数に相当する組み込み関数がないように見えますか? –

+0

@AlexCoplanいいえ、直接標準ライブラリで見つけられない直接的な同等物はありません。 – Casper

+0

@AlexCoplanしかし、 'a.product(* [a] * n)'を使うとかなり近づいてしまいます。 'n 'はPythonの' repeat = n'と同じです。 – Casper

1

私がこれを書いた後、私は本質的に同じキャスパーの解決に気づいた。いくつかは、その後aにそれをスプラット、

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"] 

キー「落とし穴」が最初aarrの配列を作成し

  • *[arr]*a、だろう..私はそれを残していますので、より読みやすい、このいずれかを見つけるかもしれません方法はproductです。 map{|e| e.join}
  • injectための速記(別名 "MAP-減らす" 名声から、 "減らす")である
  • map(&:join)、FPの柱の一つ
+0

いいね。私よりもはるかに良い:) – Casper

1

、アレイ#製品はCathesian製品になります。元の配列を追加すると同じ結果が得られます。 toklandの助けを借りて

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

、私はそれを持っている:

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

をそして、あなたはより長い文字列を生成するためにそれを使用しているとき、それはRAMを占有しないように、それは、怠け者です。

関連する問題