以深度优先顺序生成数组笛卡尔积的算法
我正在寻找一个示例,说明如何在 Ruby(类似 C 的语言或伪代码)中创建可变数量的整数数组(每个数组的长度不同)的笛卡尔积,并以特定顺序逐步遍历结果:
因此,[1,2,3],[1,2,3],[1,2,3]:
[1, 1, 1]
[2, 1, 1]
[1, 2, 1]
[1, 1, 2]
[2, 2, 1]
[1, 2, 2]
[2, 1, 2]
[2, 2, 2]
[3, 1, 1]
[1, 3, 1]
etc.
而不是我见过的典型结果(包括我下面给出的示例):
[1, 1, 1]
[2, 1, 1]
[3, 1, 1]
[1, 2, 1]
[2, 2, 1]
[3, 2, 1]
[1, 3, 1]
[2, 3, 1]
etc.
这个问题例如,在尝试了前两个位置的所有组合之前,根本不会探索第三个位置。在使用这个的代码中,这意味着即使正确的答案通常是(更大的等价物)1,1,2,它也会在找到它之前检查几百万种可能性,而不是几千种。
我正在处理一百万到数亿的结果集,因此生成它们然后排序在这里是不可行的,并且会破坏第一个示例中对它们进行排序的原因,即更快地找到正确的答案,从而打破早期的笛卡尔积生成。
以防万一它有助于澄清上述任何内容,这就是我现在的做法(这具有正确的结果和正确的性能,但不是我想要的顺序,即,它创建的结果如上面第二个列表中所示):
def cartesian(a_of_a)
a_of_a_len = a_of_a.size
result = Array.new(a_of_a_len)
j, k, a2, a2_len = nil, nil, nil, nil
i = 0
while 1 do
j, k = i, 0
while k < a_of_a_len
a2 = a_of_a[k]
a2_len = a2.size
result[k] = a2[j % a2_len]
j /= a2_len
k += 1
end
return if j > 0
yield result
i += 1
end
end
更新: 我没有说得很清楚,我正在寻找一个解决方案,在添加 3 之前检查 1,2 的所有组合,然后添加所有 3 和 1,然后添加所有 3、2 和 1,然后添加所有 3,2 。换句话说,先“水平”探索所有早期组合,然后再“垂直”探索。探索这些可能性的精确顺序,即 1,1,2 或 2,1,1,并不重要,只是在混合 3 之前探索所有 2 和 1,依此类推。
I'm looking for an example of how, in Ruby, a C like language, or pseudo code, to create the Cartesian product of a variable number of arrays of integers, each of differing length, and step through the results in a particular order:
So given, [1,2,3],[1,2,3],[1,2,3]:
[1, 1, 1]
[2, 1, 1]
[1, 2, 1]
[1, 1, 2]
[2, 2, 1]
[1, 2, 2]
[2, 1, 2]
[2, 2, 2]
[3, 1, 1]
[1, 3, 1]
etc.
Instead of the typical result I've seen (including the example I give below):
[1, 1, 1]
[2, 1, 1]
[3, 1, 1]
[1, 2, 1]
[2, 2, 1]
[3, 2, 1]
[1, 3, 1]
[2, 3, 1]
etc.
The problem with this example is that the third position isn't explored at all until all combinations of of the first two are tried. In the code that uses this, that means even though the right answer is generally (the much larger equivalent of) 1,1,2 it will examine a few million possibilities instead of just a few thousand before finding it.
I'm dealing with result sets of one million to hundreds of millions, so generating them and then sorting isn't doable here and would defeat the reason for ordering them in the first example, which is to find the correct answer sooner and so break out of the cartesian product generation earlier.
Just in case it helps clarify any of the above, here's how I do this now (this has correct results and right performance, but not the order I want, i.e., it creates results as in the second listing above):
def cartesian(a_of_a)
a_of_a_len = a_of_a.size
result = Array.new(a_of_a_len)
j, k, a2, a2_len = nil, nil, nil, nil
i = 0
while 1 do
j, k = i, 0
while k < a_of_a_len
a2 = a_of_a[k]
a2_len = a2.size
result[k] = a2[j % a2_len]
j /= a2_len
k += 1
end
return if j > 0
yield result
i += 1
end
end
UPDATE:
I didn't make it very clear that I'm after a solution where all the combinations of 1,2 are examined before 3 is added in, then all 3 and 1, then all 3, 2 and 1, then all 3,2. In other words, explore all earlier combinations "horizontally" before "vertically." The precise order in which those possibilities are explored, i.e., 1,1,2 or 2,1,1, doesn't matter, just that all 2 and 1 are explored before mixing in 3 and so on.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题精确后,这里有一个修改后的版本。我保留之前的答案,因为它也很有用并且使用不太复杂的顺序。
After the precision in the question, here's a revised version. I'm keeping the previous answer since it can be useful too and uses a less complex order.
目前尚不清楚元素
[1, 1, 3]
在您所需的输出中的位置。如果我的猜测是正确的,则以下内容有效(尽管可能可以优化)注意:如果您仍在运行 Ruby 1.8.6,请至少升级到 1.8.7(或
require '向后移植'
)It's not clear where the element
[1, 1, 3]
goes in your desired output. If my guess is right, the following works (although it could probably be optimized)Note: If you are still running Ruby 1.8.6, upgrade to at least 1.8.7 (or
require 'backports'
)嘿 Marc-André, 笛卡尔 gem 完全可以满足您的需求:
您也可以使用 **(幂)运算符来简洁
该项目托管在 github 上,并且在其 主页。
Hey Marc-André, the cartesian gem does exactly what you want:
You can also use the ** (power) operator for conciseness
The project is hosted on github and there is a link to RDoc documentation in its homepage.