假设我有一个数组[1,2,3],我希望这些数字的每个组合都不超过4.所以我会[1,2,3] .someMethod(4)和它会给我:
[1,1,1,1]
[1,1,2]
[1,3]
[2,2]
到目前为止,我有:
(1..4).flat_map{|size| [1,2,3].repeated_combination(size).to_a }
但是这给了我所有可能的组合,包括超出我给定限制的组合。有没有一种好方法可以只获得超出我限制的组合?
答案 0 :(得分:3)
arr = [1,2,3]
(arr+[0]).repeated_combination(4).select { |a| a.reduce(:+) == 4 }.map { |a| a - [0] }
#=> [[1, 3], [2, 2], [1, 1, 2], [1, 1, 1, 1]]
如果需要,将==
更改为<=
。
此答案与其他答案一样,假设arr
包含自然数字,包括1
。
答案 1 :(得分:2)
您可以使用select
方法过滤掉您不想要的数组。只需选择总和为==
4的所有数组(总和由inject
方法计算)。
all_arrs = (1..4).flat_map do |size|
[1,2,3].repeated_combination(size).to_a
end
valid_arrs = all_arrs.select do |arr|
arr.inject { |a, b| a + b } == 4
end
print valid_arrs
# Output:
# [[1, 3], [2, 2], [1, 1, 2], [1, 1, 1, 1]]
答案 2 :(得分:2)
results = (1..4).each.with_object([]) do |size, results|
[1,2,3].repeated_combination(size) do |combo|
results << combo if combo.reduce(:+) == 4
end
end
p results
--output:--
[[1, 3], [2, 2], [1, 1, 2], [1, 1, 1, 1]]
参数化算法:
def do_stuff(values, target_total)
(1..target_total).each.with_object([]) do |size, results|
values.repeated_combination(size) do |combo|
results << combo if combo.reduce(:+) == 4
end
end
end
p do_stuff([1, 2, 3], 4)
答案 3 :(得分:1)
递归方法。
def some_method(a, n)
return [[]] if n == 0
a.select { |e| e <= n }.\
flat_map { |e| some_method(a,n-e).map { |es| ([e] + es).sort } }.\
sort.\
uniq
end
p some_method([1,2,3], 4)
# => [[1, 1, 1, 1], [1, 1, 2], [1, 3], [2, 2]]
编辑:这是另一个递归版本,没有过滤重复但顺序相反。我添加了评论以使其更清晰。
def some_method(a, n)
return [[]] if n == 0 # bottom (solution) found
return [] if a.empty? || n < 0 # no solution
max = a.max
# search all solutions with biggest value
l = some_method(a, n-max).map { |e| [max] + e }
# search all solutions without biggest value
r = some_method(a-[max],n)
l + r
end
p some_method([1,2,3], 4)
# => [[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]