我想要做的是处理 n 集合,而我在下面提供的代码恰好适用于4套。
def show_combinations
@combos = []
['A', 'no A'].each do |a|
['B', 'no B'].each do |b|
['C', 'no C'].each do |c|
['D', 'no D'].each do |d|
@combos << [a, b, c, d]
end
end
end
end
end
如何重构以下代码以处理以下情况: 鉴于我有一个大小为y的数组包含大小为n的数组,我想返回所有组合。重要的是要注意每个子数组中只有一个项可以在结果中。 (例如&#34;已完成的个人资料&#34;也可以在&#34;未完成的个人资料&#34;中显示结果;)
背景:
用户可能有一些任务:例如,&#34;完成个人资料&#34;或者&#34;设置电子邮件&#34;管他呢。这些任务可以这样表示:
@task_states = [["Completed Profile, NOT Completed Profile"], ["Set up Email", "NOT set up Email"]]
然后,将@task_states传递给方法,结果应为:
[
["Completed Profile", "Set up Email"],
["Completed Profile", "NOT set up Email"],
["NOT Completed Profile", "Set up Email"],
["NOT Completed Profile", "NOT Set up Email"]
]
所以表示所有组合的数组数组。显然&#34;完成的配置文件&#34;也不能和#34;未完成的配置文件在同一个数组中,&#34;等
谢谢!
答案 0 :(得分:9)
看起来你想要计算数组的笛卡尔积。计算笛卡尔积的方法(不太令人惊讶)称为Array#product
:
@task_states.first.product(*@task_states.drop(1))
所以,例如:
['A', 'no A'].product(['B', 'no B'], ['C', 'no C'], ['D', 'no D'])
#=> [[ "A", "B", "C", "D"],
# [ "A", "B", "C", "no D"],
# [ "A", "B", "no C", "D"],
# [ "A", "B", "no C", "no D"],
# [ "A", "no B", "C", "D"],
# [ "A", "no B", "C", "no D"],
# [ "A", "no B", "no C", "D"],
# [ "A", "no B", "no C", "no D"],
# ["no A", "B", "C", "D"],
# ["no A", "B", "C", "no D"],
# ["no A", "B", "no C", "D"],
# ["no A", "B", "no C", "no D"],
# ["no A", "no B", "C", "D"],
# ["no A", "no B", "C", "no D"],
# ["no A", "no B", "no C", "D"],
# ["no A", "no B", "no C", "no D"]]
答案 1 :(得分:1)
无论如何,使用Array#product,但在Ruby的情况下,还有其他方法。这是两个。
arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
使用数学计算每个arr.size**arr.first.size
组合
def cartesian_product(arr)
n, m = arr.size, arr.first.size
(0..n**m-1).map do |x|
(n-1).downto(0).map do |i|
x, r = x.divmod(m)
arr[i][r]
end.reverse
end
end
cartesian_product arr
#=> [[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 5, 7], [1, 5, 8], [1, 5, 9],
# [1, 6, 7], [1, 6, 8], [1, 6, 9],
# [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 5, 7], [2, 5, 8], [2, 5, 9],
# [2, 6, 7], [2, 6, 8], [2, 6, 9],
# [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 5, 7], [3, 5, 8], [3, 5, 9],
# [3, 6, 7], [3, 6, 8], [3, 6, 9]]
使用递归
def cartesian_product(arr)
first, *rest = arr
return first.map { |o| [o] } if rest.empty?
c = cartesian_product(rest)
first.flat_map { |o| c.map { |a| [o] + a } }
end
cartesian_product arr
#=> same as above
在此应用程序中,arr
的每个元素(数组)都不包含重复项。在其他情况下,可能存在重复项(并且返回的产品不包含重复项),应首先计算
arr_without_dups = arr.map(&:uniq)
然后从arr_without_dups
计算组合。
答案 2 :(得分:1)
虽然提供的答案很棒,而Jörg是我接受的答案,但我想分享我的一位朋友提供给我的答案,以防其他人遇到这个问题。基本上这是Jörg的答案,但更深入。
笛卡儿产品 您要求的内容称为Cartesian Product,它已经内置Array#product。
例如:
[0, 1].product([0, 1])
# => [[0, 0], [0, 1], [1, 0], [1, 1]]
请注意,这为我们提供了所有可能的2位数字,从00-11
您可以为Array#产品提供任意数量的数组:
[0, 1].product([0, 1], [0, 1])
# => [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
请注意,这为我们提供了所有可能的3位数字,从000-111开始。
您的问题 看看你确切的问题:
["A", "no A"].product(["B", "no B"], ["C", "no C"], ["D", "no D"])
=> [["A", "B", "C", "D"],
["A", "B", "C", "no D"],
["A", "B", "no C", "D"],
["A", "B", "no C", "no D"],
["A", "no B", "C", "D"],
["A", "no B", "C", "no D"],
["A", "no B", "no C", "D"],
["A", "no B", "no C", "no D"],
["no A", "B", "C", "D"],
["no A", "B", "C", "no D"],
["no A", "B", "no C", "D"],
["no A", "B", "no C", "no D"],
["no A", "no B", "C", "D"],
["no A", "no B", "C", "no D"],
["no A", "no B", "no C", "D"],
["no A", "no B", "no C", "no D"]]
gives you all the possible combinations from "ABCD" to "noA noB noC noD"
通用解决方案 通过利用splat *运算符,我们可以使用任何通用的数组数组。
def combinations(arrays)
first, *rest = arrays
first.product(*rest)
end
然后我们可以说:
arrays_to_combine = [["A", "no A"], ["B", "no B"], ["C", "no C"], ["D", "no D"]]
combinations(arrays_to_combine)
=> [["A", "B", "C", "D"],
["A", "B", "C", "no D"],
["A", "B", "no C", "D"],
["A", "B", "no C", "no D"],
["A", "no B", "C", "D"],
["A", "no B", "C", "no D"],
["A", "no B", "no C", "D"],
["A", "no B", "no C", "no D"],
["no A", "B", "C", "D"],
["no A", "B", "C", "no D"],
["no A", "B", "no C", "D"],
["no A", "B", "no C", "no D"],
["no A", "no B", "C", "D"],
["no A", "no B", "C", "no D"],
["no A", "no B", "no C", "D"],
["no A", "no B", "no C", "no D"]]
特别感谢Thoughtbot的Joel Quenneville帮助我以及其他提供答案的人。