Ruby中Python的itertools.product相当于什么?

时间:2012-04-18 14:16:18

标签: python ruby arrays itertools

我正在寻找一种与Ruby中的Python itertools.product具有相同效果的方法。请使用以下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

但输出并不相同。单字符的工作正常(a-z),但当它进入两个字符的时候,它没有像我预期的那样工作:

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

它不会生成aababb - 所以它似乎生成所有组合而不重复字符或其他内容?

那么我应该使用什么方法来生成所有itertools.product这样的组合?

6 个答案:

答案 0 :(得分:3)

您有Array#product,就像itertools.product

答案 1 :(得分: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而不是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

答案 2 :(得分: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-1参数中重复数组product次。

所以product('abc', repeat=n)在ruby中与:

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

这就是讨厌的inject在上面的代码中的作用。它自动构建这样一个“参数数组”。但它不是非常有效的代码,所以不要试图用它来构建大型“产品”。

答案 3 :(得分:1)

在我写完之后,我注意到Casper的解决方案基本相同。有些人可能会发现这个更具可读性,所以我要离开它..

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,首先创建一个a arr的数组,然后将其展开为a方法的product个参数。
  • map(&:join),这是map{|e| e.join}
  • 的简写
  • inject(又名“减少”,来自“map-reduce”的名声),FP支柱之一

答案 4 :(得分:1)

在ruby中,Array#product产生Cathesian产品。添加原始数组会产生相同的结果。

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

答案 5 :(得分:0)

在托克兰的帮助下,我明白了:

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

它很懒,所以当你用它来生成更长的字符串时它不会占用内存。