Ruby中的排列 - 不确定如何处理

时间:2015-04-09 18:34:31

标签: ruby arrays permutation

我正在尝试输出包含1和2的排列的10元素数组的数组,例如:

 [[1,1,1,1,1,1,1,1,1,1],
 [1,1,1,1,1,1,1,1,1,2],
 [1,2,1,2,1,2,1,2,1,2],
 ...etc...
 [2,2,2,2,2,2,2,2,2,2]]

我用较小的数组做了这个,但用(10):

 a = [1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2]
 a = a.permutation(10).to_a
 print a.uniq

......这显然是一个太大的计算 - 经过一个小时的运行,它还没有完成,红宝石过程坐在12GB的内存上。还有另一种方法吗?

4 个答案:

答案 0 :(得分:6)

首先,检查该排列的大小

a.permutation(10).size
 => 670442572800

这是巨大的。你可以做的是在较小的数组上使用Array#repeated_permutations。在这里查看:

b = [1, 2] # Only unique elements
b.repeated_permutation(10) # Returns enumerable
b.repeated_permutation(10).to_a # Creates array with all of permutations

这些排列已经是唯一的(您可以通过使用和不使用Array#uniq打印它来检查)

答案 1 :(得分:4)

你失败的方法确实会产生大量数据--20!/ 10!或大约6000亿个阵列。当你输出的输出只有1024个数组

时,这显然非常浪费

你所追求的是更接近数组

上的product方法
[1,2].product(*([[1,2]]*9))

product方法通过从每个接收器及其参数中选择一个元素来生成所有可能的组合。在数组上使用splats和*方法只是为了避免写[1,2] 9次。

答案 2 :(得分:2)

编辑:不要使用此...慢一个因素(慢10倍)然后运行b= [1,2]; b.repeated_permutation(10).to_a

您正在寻找的实际上是二进制排列数组......

因此,采用这种方法,我们知道我们有2 ** 10(== 1024)个排列,转换为0到1023之间的数字。

试试这个:

1024.times.with_object([]) {|i, array| array << ( ("%10b" % (i-1) ).unpack("U*").map {|v| (v == 49) ? 2 : 1}  ) }

或者这个(稍快):

(0..1023).each.with_object([]) {|i, array| array << ( (0..9).each.with_object([]) {|j, p| p << (i[j] +1)}  ) }

您可以选择数量 - 1024.对于每个选项(i),您可以指定一个数字(i-1)并提取包含该数字的二进制代码。

在我的示例中,使用"%10b" % (i-1)将二进制代码转换为长度为10位的字符串,然后将该字符串解压缩为数组,从而提取二进制代码。我映射该数组,用数字1替换我从字符串中得到的值(空格= = 32&amp;&amp; 0 = 48),数字为1或(数字1 == 49),数字为2。

瞧。

应该有一种更好的方法来提取数字的二进制表示,但我想不出一个,因为我的睡眠很少。

答案 3 :(得分:0)

这是另一种类似于@Myst采用的方法,除了我使用Fixnum#to_s将整数转换为其二进制等价的字符串表示。

当每个数字等于1或2(或等于0或1)时,有2**n个数字带有n个数字(包括前导零)。因此,我们可以通过转换{{1}将i0之间的每个整数2**n-1映射到仅包含数字12的整数之一 - 位到01 - 位到1

在Ruby中,将2转换为二进制的一种方法是:

123

作为

123.to_s(2).to_i      #=> 1111011

我们看到,在比较2**9 #=> 512 (2**9-1).to_s(2) #=> "111111111" (2**9-1).to_s(2).to_i #=> 111111111 0511)之间的数字时,2**9-1的二进制表示将有两个前导零。由于我们需要这些前导零转换为1231,因此将每个数字的二进制表示保留为字符串和填充是很方便的带零的字符串:

2

这允许我们写:

str = 123.to_s(2).rjust(9,'0') #=> "001111011"

我们可以将它包装在一个方法中:

str.each_char.map { |c| c.eql?("0") ? 1 : 2 } }
  #=> [1, 1, 2, 2, 2, 2, 1, 2, 2]