4

itertools.productRubyのPythonと同じ効果を持つメソッドを探しています。次のPythonコードを使用します。

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.

私はそれをRubyに翻訳しようとしました:

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

しかし、出力は同じではありません。1文字のものは正常に機能しますが(az)、2文字のものになると、期待どおりに機能しません。

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

生成されていないaabaまたはbb-文字などを繰り返さずにすべての組み合わせを生成しているように見えますか?

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

4

6 に答える 6

3

itertools.productのようなArray#productがあります

于 2012-04-18T14:30:44.700 に答える
3

私は次のように書きます(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怠惰な解決策: sの代わりにsを使って簡単に書くことができますがmap、Ruby2.0の「怠惰な」ことを確認しましょう。

xs = ("a".."z").to_a
strings = 1.upto(xs.size).lazy.flat_map do |n| 
  xs.repeated_permutation(n).lazy.map(&:join)
end
于 2012-04-18T15:50:48.900 に答える
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を繰り返す必要があります。n-1product

したがってproduct('abc', repeat=n)、ルビーでは次のようになります。

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

injectそれが上記のコードで厄介なことです。そのような「引数配列」を自動的に構築します。ただし、これはあまり効率的なコードではないため、大きな「製品」を作成しようとしないでください。

于 2012-04-18T15:18:38.323 に答える
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、最初にsの配列を作成しa arr、次にそれをメソッドaの引数にスプラットしますproduct
  • map(&:join)、これはの省略形ですmap{|e| e.join}
  • inject(別名「reduce」、「map-reduce」の名声から)、FPの柱の1つ
于 2012-04-18T15:21:45.057 に答える
1

ルビーでは、Array#productはCathesian製品になります。元の配列を追加すると、同じ結果が得られます。

ar = (?a..?z).to_a
ar + ar.product(ar).map(&:join)
于 2012-04-18T17:32:45.980 に答える
0

トークランドの助けを借りて、私はそれを手に入れました:

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

そしてそれは怠惰なので、より長い文字列を生成するためにそれを使用しているときにRAMを占有しません。

于 2012-04-18T17:33:14.427 に答える