找到从数组中取出的数字的所有排列,总和为16

时间:2017-07-05 13:31:50

标签: arrays ruby circular-permutations

我想找到从[2,3,4,5,6,7,8]中取出3,4或5个数字的所有排列,允许重复,这样它们的总和就是16.所以[8, 5,3],[8,3,5]和[4,3,3,3,3]是有效的排列。还应删除循环排列,因此[3,3,3,3,4]也不会添加到答案中。 我可以在Ruby中执行此操作而不允许这样的重复:

DataFrame DF = sqlContext
                        .read()
                        .format("csv")
                        .option("delimiter", ";")
                        .option("header", "true")
                        //mv .option("inferschema", "true")
                        .load("file:///home/2.csv");

query = "select firstname, lastname, city from mytable"

DataFrame letsgo = sqlContext.sql(query);

letsgo.write().mode(SaveMode.Append).saveAsTable("mytable");

我怎么能允许重复以包括[3,3,3,3,4]?

2 个答案:

答案 0 :(得分:5)

对于所有排列,包括重复,可以使用Array#repeated_permutation

d = [2,3,4,5,6,7,8]
number_of_divisions = [3,4,5]
number_of_divisions.flat_map do |n|
  d.repeated_permutation(n).reject do |p| # no need `to_a`
    p.inject(:+) != 16
  end
end

或者更好的Array#repeated_combination

number_of_divisions.flat_map do |n|
  d.repeated_combination(n).reject do |p| # no need `to_a`
    p.inject(:+) != 16
  end
end

答案 1 :(得分:0)

重复的组合比重复的排列少得多,所以让我们找到与给定值相加的重复组合,然后对每个组合进行置换。此外,通过在计算的几个步骤中的每一步应用uniq,我们可以显着减少所考虑的重复组合和排列的数量。

<强>代码

require 'set'

def rep_perms_for_all(arr, n_arr, tot)
  n_arr.flat_map { |n| rep_perms_for_1(arr, n, tot) }
end

def rep_perms_for_1(arr, n, tot)
   rep_combs_to_rep_perms(rep_combs_for_1(arr, n, tot)).uniq
end

def rep_combs_for_1(arr, n, tot)
  arr.repeated_combination(n).uniq.select { |c| c.sum == tot }
end

def rep_combs_to_rep_perms(combs)
  combs.flat_map { |c| comb_to_perms(c) }.uniq
end

def comb_to_perms(comb)
  comb.permutation(comb.size).uniq.uniq do |p| 
    p.size.times.with_object(Set.new) { |i,s| s << p.rotate(i) } 
  end
end

<强>实施例

rep_perms_for_all([2,3,4,5], [3], 12)
  #=> [[2, 5, 5], [3, 4, 5], [3, 5, 4], [4, 4, 4]]
rep_perms_for_all([2,3,4,5,6,7,8], [3,4,5], 16).size
  #=> 93
rep_perms_for_all([2,3,4,5,6,7,8], [3,4,5], 16)
  #=> [[2, 6, 8], [2, 8, 6], [2, 7, 7], [3, 5, 8], [3, 8, 5], [3, 6, 7],
  #    [3, 7, 6], [4, 4, 8], [4, 5, 7], [4, 7, 5], [4, 6, 6], [5, 5, 6],
  #    [2, 2, 4, 8], [2, 2, 8, 4], [2, 4, 2, 8], [2, 2, 5, 7], [2, 2, 7, 5],
  #    [2, 5, 2, 7], [2, 2, 6, 6], [2, 6, 2, 6], [2, 3, 3, 8], [2, 3, 8, 3], 
  #    ...
  #    [3, 3, 3, 7], [3, 3, 4, 6], [3, 3, 6, 4], [3, 4, 3, 6], [3, 3, 5, 5], 
  #    [3, 5, 3, 5], [3, 4, 4, 5], [3, 4, 5, 4], [3, 5, 4, 4], [4, 4, 4, 4],
  #    ...
  #    [2, 2, 4, 5, 3], [2, 2, 5, 3, 4], [2, 2, 5, 4, 3], [2, 3, 2, 4, 5],
  #    [2, 3, 2, 5, 4], [2, 3, 4, 2, 5], [2, 3, 5, 2, 4], [2, 4, 2, 5, 3],
  #    ...
  #    [2, 5, 3, 3, 3], [2, 3, 3, 4, 4], [2, 3, 4, 3, 4], [2, 3, 4, 4, 3],
  #    [2, 4, 3, 3, 4], [2, 4, 3, 4, 3], [2, 4, 4, 3, 3], [3, 3, 3, 3, 4]]

<强>解释

rep_combs_for_1使用方法Enumerable#sum,它在Ruby v2.4中首次亮相。对于早期版本,请使用c.reduce(:0) == tot

comb_to_perms中,第一个uniq只会删除重复项。带有块的第二个uniq除去了可以通过旋转任何其他p.size元素获得的p-1元素(数组)中的所有元素。例如,

p = [1,2,3]
p.size.times.with_object(Set.new) { |i,s| s << p.rotate(i) }
  #=> #<Set: {[1, 2, 3], [2, 3, 1], [3, 1, 2]}>