2012-04-18 94 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。

相关问题