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

但是输出不一样。一个字符的工作正常(az),但是当它进入两个字符的时候,它不能像我预期的那样工作:

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

它没有生成aa,ba或者bb- 所以它似乎正在生成所有组合而不重复字符或其他东西?

那么我应该使用什么方法来生成所有的组合,就像itertools.product在 Python 中所做的那样?

4

6 回答 6

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

一个懒惰的解决方案:你可以很容易地用eachs 而不是 s 来编写它map,但是让我们检查一下 Ruby 2.0 中的“lazy”:

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 回答
3

你有Array#product这就像itertools.product

于 2012-04-18T14:30:44.700 回答
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

在 ruby​​ 中也是product('abc', repeat=n)一样的:

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

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

于 2012-04-18T15:18:38.323 回答
1

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

ar = (?a..?z).to_a
ar + ar.product(ar).map(&:join)
于 2012-04-18T17:32:45.980 回答
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,它首先创建一个 s 数组a arr,然后将其放入方法a的参数中product
  • map(&:join),这是一个简写形式map{|e| e.join}
  • inject(又名“reduce”,来自“map-reduce”名声),FP 支柱之一
于 2012-04-18T15:21:45.057 回答
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。

于 2012-04-18T17:33:14.427 回答