Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Ruby中使用循环输出所有可能的组合?_Ruby_Loops_Combinations - Fatal编程技术网

如何在Ruby中使用循环输出所有可能的组合?

如何在Ruby中使用循环输出所有可能的组合?,ruby,loops,combinations,Ruby,Loops,Combinations,我刚开始学习编程,正在尝试编写一个输出所有可能组合的函数。到目前为止,我已经能够找到所有可能的大小2的组合,但我不知道如何让代码开放,以处理更大的大小组合。某种递归会有用吗 我知道我可以使用内置的组合方法,但我只是想知道如何从头开始编写它。任何建议都将不胜感激。谢谢 def two_combos(input) list = [] for index1 in (0...input.length) for index2 in (0...input.length)

我刚开始学习编程,正在尝试编写一个输出所有可能组合的函数。到目前为止,我已经能够找到所有可能的大小2的组合,但我不知道如何让代码开放,以处理更大的大小组合。某种递归会有用吗

我知道我可以使用内置的组合方法,但我只是想知道如何从头开始编写它。任何建议都将不胜感激。谢谢

def two_combos(input)
    list = []
    for index1 in (0...input.length)
        for index2 in (0...input.length)
            if input[index1] != input[index2]
                if list.include?([input[index2],input[index1]])==false
                    list << [input[index1],input[index2]]
                end
            end
        end
    end
    return list
end


two_combos(["A","B","C"])
#outputs
=> [["A", "B"], ["A", "C"], ["B", "C"]]
#Missing
["A","B","C"]
def两个_组合(输入)
列表=[]
对于index1英寸(0…输入长度)
对于index2英寸(0…输入长度)
如果输入[index1]!=输入[index2]
if list.include?([input[index2],input[index1]])==false
列表[“A”、“B”]、[“A”、“C”]、[“B”、“C”]]
#失踪
[“A”、“B”、“C”]

这里是递归算法

def combinations(array, size)
  fail "size is too big" if size > array.size

  combination([], [], array, size)
end

def combination(result, step, array, size)
  steps = size - step.size
  array[0..-steps].each_with_index do |a, i|
    next_step = step + [a]
    if next_step.size < size
      combination(result, next_step, array[i+1..-1], size)
    else
      result << next_step
    end
  end
  result
end

a = ("A".."E").to_a
p combinations(a, 1)
# [["A"], ["B"], ["C"], ["D"], ["E"]]
p combinations(a, 2)
# [["A", "B"], ["A", "C"], ["A", "D"], ["A", "E"], ["B", "C"], ["B", "D"], ["B", "E"], ["C", "D"], ["C", "E"], ["D", "E"]]
p combinations(a, 3)
# [["A", "B", "C"], ["A", "B", "D"], ["A", "B", "E"], ["A", "C", "D"], ["A", "C", "E"], ["A", "D", "E"], ["B", "C", "D"], ["B", "C", "E"], ["B", "D", "E"], ["C", "D", "E"]]
p combinations(a, 4)
# [["A", "B", "C", "D"], ["A", "B", "C", "E"], ["A", "B", "D", "E"], ["A", "C", "D", "E"], ["B", "C", "D", "E"]]
def组合(阵列、大小)
如果大小>array.size,则“大小太大”失败
组合([]、[]、阵列、大小)
结束
def组合(结果、步长、阵列、大小)
步长=大小-步长.size
数组[0..-steps]。每个_都有_索引do | a,i|
下一步=步骤+[a]
如果下一步的步长结果我可以想出一种不使用递归计算给定大小的组合的方法,但它不是特别有效。但是,如果您想要获得所有大小的所有组合(有时称为“功率”),那么它是非常有效的[编辑:显然不是。请参阅基准。]我的理解是,问题涉及后者,但我将给出每个问题的方法

如果
索引
包含
n个
元素,则每个组合都可以由
n个
元素数组表示,该数组的元素为零或一,
1
表示该组合包含该索引处的元素,“0”(或前导空格)表示不包含该元素。因此,我们可以通过简单地生成长度为
n
的所有二进制数,将每个二进制数从其字符串表示(带前导零)转换为
“0”和
“1”的数组来生成所有大小的所有组合集,用它们的索引位置替换
“1”
,删除
“0”
,并在给定索引位置提取
索引的元素

代码

def all_combos(sz)
  [*(0..2**sz-1)].map { |i| ("%0#{sz}b" % i).chars }
                 .map { |a| a.each_with_index
                             .select { |n,ndx| n=="1" }.map(&:last) }
end

def combos(input, n, all_combos)
  all_combos.select { |c| c.size == n }.map { |c| input.values_at(*c) }
end

def power(input, all_combos)
  all_combos.map { |c| input.values_at(*c) }
end
input = %w{b e a r s}
   #=> ["b", "e", "a", "r", "s"]
ac = all_combos(input.size)
  #=> [[], [4], [3], [3, 4], [2], [2, 4], [2, 3], [2, 3, 4],
  #    [1], [1, 4], [1, 3], [1, 3, 4], [1, 2], [1, 2, 4], [1, 2, 3],
  #    [1, 2, 3, 4], [0], [0, 4], [0, 3], [0, 3, 4], [0, 2], [0, 2, 4],
  #    [0, 2, 3], [0, 2, 3, 4], [0, 1], [0, 1, 4], [0, 1, 3], [0, 1, 3, 4],
  #    [0, 1, 2], [0, 1, 2, 4], [0, 1, 2, 3], [0, 1, 2, 3, 4]]

(0..input.size).each { |i| puts "size #{i}"; p combos(input, i, ac) }
  # size 0
  # [[]]
  # size 1
  # [["s"], ["r"], ["a"], ["e"], ["b"]]
  # size 2
  # [["r", "s"], ["a", "s"], ["a", "r"], ["e", "s"], ["e", "r"],
  #    ["e", "a"], ["b", "s"], ["b", "r"], ["b", "a"], ["b", "e"]]
  # size 3
  # [["a", "r", "s"], ["e", "r", "s"], ["e", "a", "s"], ["e", "a", "r"],
  #    ["b", "r", "s"], ["b", "a", "s"], ["b", "a", "r"], ["b", "e", "s"],
  #    ["b", "e", "r"], ["b", "e", "a"]]
  # size 4
  # [["e", "a", "r", "s"], ["b", "a", "r", "s"], ["b", "e", "r", "s"], 
  #    ["b", "e", "a", "s"], ["b", "e", "a", "r"]]
  # size 5
  # [["b", "e", "a", "r", "s"]]

power(input, ac)
  #=> [[], ["s"], ["r"], ["r", "s"], ["a"], ["a", "s"], ["a", "r"],
  #    ["a", "r", "s"], ["e"], ["e", "s"], ["e", "r"], ["e", "r", "s"],
  #    ["e", "a"], ["e", "a", "s"], ["e", "a", "r"], ["e", "a", "r", "s"],
  #    ["b"], ["b", "s"], ["b", "r"], ["b", "r", "s"], ["b", "a"],
  #    ["b", "a", "s"], ["b", "a", "r"], ["b", "a", "r", "s"], ["b", "e"],
  #    ["b", "e", "s"], ["b", "e", "r"], ["b", "e", "r", "s"], ["b", "e", "a"],
  #    ["b", "e", "a", "s"], ["b", "e", "a", "r"], ["b", "e", "a", "r", "s"]]
include Methods
@methods = Methods.public_instance_methods(false)
  #=> [:ruby, :todd, :fl00r, :cary]
require 'benchmark'

@indent = methods.map { |m| m.to_s.size }.max

[10, 15, 20].each do |n|
  puts "\nn = #{n}"
  arr = test_array(n)
  Benchmark.bm(@indent) do |bm|
    @methods.each do |m|
      bm.report m.to_s do
        compute(arr, m).size
      end
    end
  end
end
示例

def all_combos(sz)
  [*(0..2**sz-1)].map { |i| ("%0#{sz}b" % i).chars }
                 .map { |a| a.each_with_index
                             .select { |n,ndx| n=="1" }.map(&:last) }
end

def combos(input, n, all_combos)
  all_combos.select { |c| c.size == n }.map { |c| input.values_at(*c) }
end

def power(input, all_combos)
  all_combos.map { |c| input.values_at(*c) }
end
input = %w{b e a r s}
   #=> ["b", "e", "a", "r", "s"]
ac = all_combos(input.size)
  #=> [[], [4], [3], [3, 4], [2], [2, 4], [2, 3], [2, 3, 4],
  #    [1], [1, 4], [1, 3], [1, 3, 4], [1, 2], [1, 2, 4], [1, 2, 3],
  #    [1, 2, 3, 4], [0], [0, 4], [0, 3], [0, 3, 4], [0, 2], [0, 2, 4],
  #    [0, 2, 3], [0, 2, 3, 4], [0, 1], [0, 1, 4], [0, 1, 3], [0, 1, 3, 4],
  #    [0, 1, 2], [0, 1, 2, 4], [0, 1, 2, 3], [0, 1, 2, 3, 4]]

(0..input.size).each { |i| puts "size #{i}"; p combos(input, i, ac) }
  # size 0
  # [[]]
  # size 1
  # [["s"], ["r"], ["a"], ["e"], ["b"]]
  # size 2
  # [["r", "s"], ["a", "s"], ["a", "r"], ["e", "s"], ["e", "r"],
  #    ["e", "a"], ["b", "s"], ["b", "r"], ["b", "a"], ["b", "e"]]
  # size 3
  # [["a", "r", "s"], ["e", "r", "s"], ["e", "a", "s"], ["e", "a", "r"],
  #    ["b", "r", "s"], ["b", "a", "s"], ["b", "a", "r"], ["b", "e", "s"],
  #    ["b", "e", "r"], ["b", "e", "a"]]
  # size 4
  # [["e", "a", "r", "s"], ["b", "a", "r", "s"], ["b", "e", "r", "s"], 
  #    ["b", "e", "a", "s"], ["b", "e", "a", "r"]]
  # size 5
  # [["b", "e", "a", "r", "s"]]

power(input, ac)
  #=> [[], ["s"], ["r"], ["r", "s"], ["a"], ["a", "s"], ["a", "r"],
  #    ["a", "r", "s"], ["e"], ["e", "s"], ["e", "r"], ["e", "r", "s"],
  #    ["e", "a"], ["e", "a", "s"], ["e", "a", "r"], ["e", "a", "r", "s"],
  #    ["b"], ["b", "s"], ["b", "r"], ["b", "r", "s"], ["b", "a"],
  #    ["b", "a", "s"], ["b", "a", "r"], ["b", "a", "r", "s"], ["b", "e"],
  #    ["b", "e", "s"], ["b", "e", "r"], ["b", "e", "r", "s"], ["b", "e", "a"],
  #    ["b", "e", "a", "s"], ["b", "e", "a", "r"], ["b", "e", "a", "r", "s"]]
include Methods
@methods = Methods.public_instance_methods(false)
  #=> [:ruby, :todd, :fl00r, :cary]
require 'benchmark'

@indent = methods.map { |m| m.to_s.size }.max

[10, 15, 20].each do |n|
  puts "\nn = #{n}"
  arr = test_array(n)
  Benchmark.bm(@indent) do |bm|
    @methods.each do |m|
      bm.report m.to_s do
        compute(arr, m).size
      end
    end
  end
end

此实现类似于二进制递归计数:

def combinations(items)
  return [] unless items.any?
  prefix = items[0]
  suffixes = combinations(items[1..-1])
  [[prefix]] + suffixes + suffixes.map {|item| [prefix] + item }
end

> combinations(%w(a b c))
=> [["a"], ["b"], ["c"], ["b", "c"], ["a", "b"], ["a", "c"], ["a", "b", "c"]]
在每个阶段,组合都是以下各项的串联:

  • 仅第一个元素
  • 以下元素的组合(元素1..n-1)
  • 第一个元素与以下元素的组合组合

  • 先生们,启动你们的引擎

    比较的方法

    module Methods
      def ruby(array)
        (0..array.size).each_with_object([]) { |i,a|
           a.concat(array.combination(i).to_a) }
      end
    

    测试数据

    def test_array(n)
      [*1..n]
    end
    
    助手

    def compute(arr, meth)
      send(meth, arr)
    end  
    
    def compute_sort(arr, meth)
      compute(arr, meth).map(&:sort).sort
    end
    
    arr = test_array(8)
    
    a = compute_sort(arr, @methods.first) 
    puts @methods[1..-1].all? { |m| a == compute_sort(arr, m) }
      #=> true
    
    n = 10
                                     user     system      total        real
    ruby                         0.000000   0.000000   0.000000 (  0.000312)
    todd                         0.000000   0.000000   0.000000 (  0.001611)
    fl00r                        0.000000   0.000000   0.000000 (  0.002675)
    cary                         0.010000   0.000000   0.010000 (  0.010026)
    
    n = 15
                                     user     system      total        real
    ruby                         0.010000   0.000000   0.010000 (  0.010742)
    todd                         0.070000   0.010000   0.080000 (  0.081821)
    fl00r                        0.080000   0.000000   0.080000 (  0.076030)
    cary                         0.430000   0.020000   0.450000 (  0.450382)
    
    n = 20
                                     user     system      total        real
    ruby                         0.310000   0.040000   0.350000 (  0.350484)
    todd                         2.360000   0.130000   2.490000 (  2.487493)
    fl00r                        2.320000   0.090000   2.410000 (  2.405377)
    cary                        21.420000   0.620000  22.040000 ( 22.053303)
    
    包括模块

    def all_combos(sz)
      [*(0..2**sz-1)].map { |i| ("%0#{sz}b" % i).chars }
                     .map { |a| a.each_with_index
                                 .select { |n,ndx| n=="1" }.map(&:last) }
    end
    
    def combos(input, n, all_combos)
      all_combos.select { |c| c.size == n }.map { |c| input.values_at(*c) }
    end
    
    def power(input, all_combos)
      all_combos.map { |c| input.values_at(*c) }
    end
    
    input = %w{b e a r s}
       #=> ["b", "e", "a", "r", "s"]
    ac = all_combos(input.size)
      #=> [[], [4], [3], [3, 4], [2], [2, 4], [2, 3], [2, 3, 4],
      #    [1], [1, 4], [1, 3], [1, 3, 4], [1, 2], [1, 2, 4], [1, 2, 3],
      #    [1, 2, 3, 4], [0], [0, 4], [0, 3], [0, 3, 4], [0, 2], [0, 2, 4],
      #    [0, 2, 3], [0, 2, 3, 4], [0, 1], [0, 1, 4], [0, 1, 3], [0, 1, 3, 4],
      #    [0, 1, 2], [0, 1, 2, 4], [0, 1, 2, 3], [0, 1, 2, 3, 4]]
    
    (0..input.size).each { |i| puts "size #{i}"; p combos(input, i, ac) }
      # size 0
      # [[]]
      # size 1
      # [["s"], ["r"], ["a"], ["e"], ["b"]]
      # size 2
      # [["r", "s"], ["a", "s"], ["a", "r"], ["e", "s"], ["e", "r"],
      #    ["e", "a"], ["b", "s"], ["b", "r"], ["b", "a"], ["b", "e"]]
      # size 3
      # [["a", "r", "s"], ["e", "r", "s"], ["e", "a", "s"], ["e", "a", "r"],
      #    ["b", "r", "s"], ["b", "a", "s"], ["b", "a", "r"], ["b", "e", "s"],
      #    ["b", "e", "r"], ["b", "e", "a"]]
      # size 4
      # [["e", "a", "r", "s"], ["b", "a", "r", "s"], ["b", "e", "r", "s"], 
      #    ["b", "e", "a", "s"], ["b", "e", "a", "r"]]
      # size 5
      # [["b", "e", "a", "r", "s"]]
    
    power(input, ac)
      #=> [[], ["s"], ["r"], ["r", "s"], ["a"], ["a", "s"], ["a", "r"],
      #    ["a", "r", "s"], ["e"], ["e", "s"], ["e", "r"], ["e", "r", "s"],
      #    ["e", "a"], ["e", "a", "s"], ["e", "a", "r"], ["e", "a", "r", "s"],
      #    ["b"], ["b", "s"], ["b", "r"], ["b", "r", "s"], ["b", "a"],
      #    ["b", "a", "s"], ["b", "a", "r"], ["b", "a", "r", "s"], ["b", "e"],
      #    ["b", "e", "s"], ["b", "e", "r"], ["b", "e", "r", "s"], ["b", "e", "a"],
      #    ["b", "e", "a", "s"], ["b", "e", "a", "r"], ["b", "e", "a", "r", "s"]]
    
    include Methods
    @methods = Methods.public_instance_methods(false)
      #=> [:ruby, :todd, :fl00r, :cary]
    
    require 'benchmark'
    
    @indent = methods.map { |m| m.to_s.size }.max
    
    [10, 15, 20].each do |n|
      puts "\nn = #{n}"
      arr = test_array(n)
      Benchmark.bm(@indent) do |bm|
        @methods.each do |m|
          bm.report m.to_s do
            compute(arr, m).size
          end
        end
      end
    end
    
    确认方法返回相同的值

    def compute(arr, meth)
      send(meth, arr)
    end  
    
    def compute_sort(arr, meth)
      compute(arr, meth).map(&:sort).sort
    end
    
    arr = test_array(8)
    
    a = compute_sort(arr, @methods.first) 
    puts @methods[1..-1].all? { |m| a == compute_sort(arr, m) }
      #=> true
    
    n = 10
                                     user     system      total        real
    ruby                         0.000000   0.000000   0.000000 (  0.000312)
    todd                         0.000000   0.000000   0.000000 (  0.001611)
    fl00r                        0.000000   0.000000   0.000000 (  0.002675)
    cary                         0.010000   0.000000   0.010000 (  0.010026)
    
    n = 15
                                     user     system      total        real
    ruby                         0.010000   0.000000   0.010000 (  0.010742)
    todd                         0.070000   0.010000   0.080000 (  0.081821)
    fl00r                        0.080000   0.000000   0.080000 (  0.076030)
    cary                         0.430000   0.020000   0.450000 (  0.450382)
    
    n = 20
                                     user     system      total        real
    ruby                         0.310000   0.040000   0.350000 (  0.350484)
    todd                         2.360000   0.130000   2.490000 (  2.487493)
    fl00r                        2.320000   0.090000   2.410000 (  2.405377)
    cary                        21.420000   0.620000  22.040000 ( 22.053303)
    
    基准代码

    def all_combos(sz)
      [*(0..2**sz-1)].map { |i| ("%0#{sz}b" % i).chars }
                     .map { |a| a.each_with_index
                                 .select { |n,ndx| n=="1" }.map(&:last) }
    end
    
    def combos(input, n, all_combos)
      all_combos.select { |c| c.size == n }.map { |c| input.values_at(*c) }
    end
    
    def power(input, all_combos)
      all_combos.map { |c| input.values_at(*c) }
    end
    
    input = %w{b e a r s}
       #=> ["b", "e", "a", "r", "s"]
    ac = all_combos(input.size)
      #=> [[], [4], [3], [3, 4], [2], [2, 4], [2, 3], [2, 3, 4],
      #    [1], [1, 4], [1, 3], [1, 3, 4], [1, 2], [1, 2, 4], [1, 2, 3],
      #    [1, 2, 3, 4], [0], [0, 4], [0, 3], [0, 3, 4], [0, 2], [0, 2, 4],
      #    [0, 2, 3], [0, 2, 3, 4], [0, 1], [0, 1, 4], [0, 1, 3], [0, 1, 3, 4],
      #    [0, 1, 2], [0, 1, 2, 4], [0, 1, 2, 3], [0, 1, 2, 3, 4]]
    
    (0..input.size).each { |i| puts "size #{i}"; p combos(input, i, ac) }
      # size 0
      # [[]]
      # size 1
      # [["s"], ["r"], ["a"], ["e"], ["b"]]
      # size 2
      # [["r", "s"], ["a", "s"], ["a", "r"], ["e", "s"], ["e", "r"],
      #    ["e", "a"], ["b", "s"], ["b", "r"], ["b", "a"], ["b", "e"]]
      # size 3
      # [["a", "r", "s"], ["e", "r", "s"], ["e", "a", "s"], ["e", "a", "r"],
      #    ["b", "r", "s"], ["b", "a", "s"], ["b", "a", "r"], ["b", "e", "s"],
      #    ["b", "e", "r"], ["b", "e", "a"]]
      # size 4
      # [["e", "a", "r", "s"], ["b", "a", "r", "s"], ["b", "e", "r", "s"], 
      #    ["b", "e", "a", "s"], ["b", "e", "a", "r"]]
      # size 5
      # [["b", "e", "a", "r", "s"]]
    
    power(input, ac)
      #=> [[], ["s"], ["r"], ["r", "s"], ["a"], ["a", "s"], ["a", "r"],
      #    ["a", "r", "s"], ["e"], ["e", "s"], ["e", "r"], ["e", "r", "s"],
      #    ["e", "a"], ["e", "a", "s"], ["e", "a", "r"], ["e", "a", "r", "s"],
      #    ["b"], ["b", "s"], ["b", "r"], ["b", "r", "s"], ["b", "a"],
      #    ["b", "a", "s"], ["b", "a", "r"], ["b", "a", "r", "s"], ["b", "e"],
      #    ["b", "e", "s"], ["b", "e", "r"], ["b", "e", "r", "s"], ["b", "e", "a"],
      #    ["b", "e", "a", "s"], ["b", "e", "a", "r"], ["b", "e", "a", "r", "s"]]
    
    include Methods
    @methods = Methods.public_instance_methods(false)
      #=> [:ruby, :todd, :fl00r, :cary]
    
    require 'benchmark'
    
    @indent = methods.map { |m| m.to_s.size }.max
    
    [10, 15, 20].each do |n|
      puts "\nn = #{n}"
      arr = test_array(n)
      Benchmark.bm(@indent) do |bm|
        @methods.each do |m|
          bm.report m.to_s do
            compute(arr, m).size
          end
        end
      end
    end
    
    测试(秒)


    我只得出一个明确的结论。

    使用数组置换如何?对不起,我没有全部读过。我知道你想写一个自定义的。祝你好运您可能必须使用递归方法。微小的遗漏,很容易修复:no
    []
    。将删除此注释。@CarySwoveland您能想出一种方法在结果中包含
    []
    ,而不使代码量增加一倍吗?我不能!一个简单的方法是像我在添加的基准测试中所做的那样,在这里我创建了一个调用
    置换
    的方法,然后将
    []
    添加到返回的数组中。顺便说一句,
    permutations
    在这里不是一个好名字,因为您正在计算组合。(如果
    [1,2,3]
    是排列的一个元素,那么
    [1,3,2]
    [2,1,3]
    [2,3,1]
    [3,1,2]
    [3,2,1]
    )@CarySwoveland关于排列与组合的好观点——高中数学太早了!关于
    []
    :我正在寻找一种方法来改变算法,使其自然地包含
    []
    ,但我仍然无法找到它。您需要一个小的修复:
    p组合(a,0)=>[[“a”]]
    做得好!了解不同方法的性能总是很有趣的。对于GRIN,与
    数组#组合的本机实现相比如何?(你可能需要增加n来注册一些东西。)好主意。我加上去了。