生成安排给定数量元素的所有方式

时间:2014-05-18 20:55:23

标签: ruby combinations

我想生成所有可能的方法来安排一定数量的元素number_of_elements。现在,我只想打印出可能性upto的所有可能性。

编辑:说number_of_elements为3,然后我想要所有可能的方法来安排012数字可以出现0次或多次,订单很重要。所以0!= 00!= 01!= 10!= 11

例如,all_combinations(3,14)应该打印:

0
1
2
00
01
02
10
11
12
20
21
22
000 # updated. I originally put 100 here by mistake.
001
...

我试过了:

def all_combinations(number_of_elements, upto)
  0.upto upto do |n|
    puts n.to_s(number_of_elements)
  end
end

all_combinations(3, 10)

我的想法是获取所有整数,将它们转换为基数number_of_elements并将该数字解释为可能性。 它几乎可以工作,除了我缺少一些元素。

(这是我上面代码得到的输出):

0
1
2
   # 00 missing
   # 01 missing
   # 02 missing
10
11
12
20
21
22
   # 0.. elements missing
100
101
...

任何想法或其他简单的方法来获得这些?

5 个答案:

答案 0 :(得分:1)

授予this question。以下是对我答案的略微修改。

class Numeric
  def sequence b
    s, q = "", self
    (q, r = (q - 1).divmod(b)) && s.prepend(r.to_s) until q.zero?
    s
  end
end

def foo(number_of_elements, upto)
  1.upto upto do |n|
    puts n.sequence(number_of_elements)
  end
end

foo(3, 14)

结果:

0
1
2
00
01
02
10
11
12
20
21
22
000
001

答案 1 :(得分:1)

您可以使用Array#repeated_permuation执行此操作:

def all_combinations(nbr, upto)
  (1..nbr).each_with_object([]) do |n, arr|
    arr.concat(('0'...nbr.to_s).to_a
                               .repeated_permutation(n)
                               .to_a) if arr.size < upto
  end.first(upto).each { |e| puts e.join }
end

all_combinations(3, 14)
0
1
2
00
01
02
10
11
12
20
21
22
000
001

如果number_of_elements很大,这种方法的缺点是可能会向阵列arr添加大量排列,但不会使用。另一种方法是创建一个枚举器对象,该对象可用于使用Enumerator#nextEnumerator#peek枚举重复的排列,精确枚举upto个值。我向permutation here展示了如何做到这一点,并解释了repeated_permutation如何更容易。

答案 2 :(得分:0)

可能最简单的攻击方法是 - 不幸的是,如果你不熟悉递归 - 使用递归方法。

你想在每个可能的地方尝试每一个可能的数字,基本上。

def all_combinations(s, number_of_elements, upto)
  if number_of_elements < 1
    puts s
    return
  end
  0.upto upto - 1 do |n|
    all_combinations(s + n.to_s, number_of_elements - 1, upto)
  end
end
all_combinations("", 3, 10)

前提是,无论你在哪个阶段(s;想象它是12),你想要将所有可能的数字附加到它并继续。但是,我们不想永远地去,我们放置的每个数字都会让我们更接近,所以减少number_of_elements;当number_of_elements为零时,我们没有别的事可做,所以是时候打印了。

一些问题:   - upto不知道它有多大。如果你拨打all_combinations("", 3, 500),你就会得到格式错误的字符串。   - 如前所述,如果您只是在学习编程,那么递归可能不是潜水的最佳选择。   - 同样地,如果这是用于家庭作业而你没有覆盖递归,这将是一个好的迹象,你要求互联网上的随机人员寻求帮助,这可能不会产生理想的等级

但是,有了这些警告,我认为这是最简单的方法。想到的其他一切都需要手动跟踪位置和最近的输出,这些...... ick

答案 3 :(得分:0)

以下是使用repeated_permutations

执行此操作的简明方法
def all_combinations(number_of_elements, upto)
  elements = (0...number_of_elements).map(&:to_s)
  combinations = (1..1.0/0).lazy.flat_map do |i|
    elements.repeated_permutation(i).map do |permutation|
       permutation.join
    end
  end
  puts combinations.take(upto).to_a
end

all_combinations(3, 14)
0
1
2
00
01
02
10
11
12
20
21
22
000
001

答案 4 :(得分:0)

这是另一种方法,使用String#to_iFixnum#to_s,每个参数base(默认为10)设置等于“元素数量”:

def all_combinations(n_elements, upto)
  s = '10'
  upto.times.with_object([]) do |_,arr|
    arr << s
    candidate = (s.to_i(n_elements)+1).to_s(3)
    (candidate = '1'+'0' * s.size) unless candidate[0] == '1'
    s = candidate
  end.map { |str| str[1..-1] }
end

all_combinations(3, 15)
  #=> ["0",   "1",   "2",
  #   "00",  "01",  "02",
  #   "10",  "11",  "12",
  #   "20",  "21",  "22",
  #  "000", "001", "002"]
相关问题