【问题标题】:Generate unique combinations from multiple arrays/vectors从多个数组/向量生成唯一组合
【发布时间】:2018-04-10 09:02:45
【问题描述】:

我有 800 个数据文件,每个文件包含 8 行整数,例如

17,1,2,3,4,5,6,7,10,11,12,13,15,16,20,22,24,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
16,1,2,3,4,5,6,7,8,9,10,11,12,16,17,21,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
23,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,23,25,26,28,29,35,36,,,,,,,,,,,,,,,,,,,,,,,,,,
27,8,9,11,12,13,14,15,17,19,20,21,22,23,24,26,27,28,29,30,31,32,34,37,39,40,41,42,,,,,,,,,,,,,,,,,,,,,,
27,14,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,42,43,44,,,,,,,,,,,,,,,,,,,,,,
24,20,24,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,,,,,,,,,,,,,,,,,,,,,,,,,
16,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
14,35,37,38,39,40,41,42,43,44,45,46,47,48,49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

每行有 50 个元素,每行的第一个元素是数字计数,即第 1 行的 17 表示该行中有 17 个数字 1,2,3,4,5,6,7,10,11,12, 13、15、16、20、22、24、26。每行中的数字是唯一的,按升序排列,范围为 1~49。 我的任务是从这 8 行生成唯一 8 个数字组合的列表 即 A,B,C,D,E,F,G,H 第 1 行的 A,第 2 行的 B ... 第 8 行的 H

将生成24,517,914,624(17*16*23*27*27*24*16*14)个条目:

1,1,4,8,14,20,33,35
...
1,1,4,8,14,20,33,49
....
1,2,4,8,14,20,33,35
...
2,1,4,8,14,20,33,35
...

然后将 24,517,914,624 个条目列表处理如下:

i) 删除具有重复数字的条目,例如1,1,4,8,14,20,33,35 和 1,1,4,8,14,20,33,49 将被移除

ii) 按升序对每个条目中的编号进行排序,例如2,1,4,8,14,20,33,35 将变为 1,2,4,8,14,20,33,35

iii) 删除重复的条目,例如2,1,4,8,14,20,33,35 排序后与 1,2,4,8,14,20,33,35 相同,因此只有 1,2,4,8,14 的 1 个条目,20,33,35 将被保留 经过上述过程,可能还剩下大约1000万个条目(这是我想要的结果)

但是。处理 24,517,914,624 个条目数组几乎是不可能的任务, 因此我尝试了以下两种方法来解决问题(尝试删除具有重复数字的条目并为每个条目排序。

1)蛮力方法,使用8个嵌套for循环生成组合:

for (int i = 0; i < LineArr[0][0]; i++) {
 for (int j = 0; j < LineArr[1][0]; j++) {
  for (int k = 0; k < LineArr[2][0]; k++) {
   for (int l = 0; l < LineArr[3][0]; l++) {
    for (int m = 0; m < LineArr[4][0]; m++) {
     for (int n = 0; n < LineArr[5][0]; n++) {
      for (int o = 0; o < LineArr[6][0]; o++) {
       for (int p = 0; p < LineArr[7][0]; p++) {
        MyRes[0]=LineArr[0][i]
        MyRes[1]=LineArr[1][j]
        MyRes[2]=LineArr[2][k]
        MyRes[3]=LineArr[3][l]
        MyRes[4]=LineArr[4][m]
        MyRes[5]=LineArr[5][n]
        MyRes[6]=LineArr[6][o]
        MyRes[7]=LineArr[7][p]
        // Sort number of MyRes and discard if it contains duplicate numbers
        // store valid combination in a temp array/vector
        }}}}}}}}
        // remove duplicate entries in the temp array/vector ('unique' the temp array)

2) 逐步方法 不是一次生成 8 个数字组合,而是从前 2 行生成 2 个数字组合,对每个条目中的数字进行排序,删除具有重复数字的条目并统一列表 输出将是这样的:

1,2
1,3
1,4

1,1 2,2 将被删除,4,1 将变为 1,4 并删除重复条目。

那么上面的列表将与第3行组合形成3个数字组合,同时对重复数字的条目进行排序和删除,并统一列表。 将上述应用到 4,5,6...8 行,形成 4,5,6...8 个数字组合

由于这是自动化项目的一部分,因此 AutoIt 在整个项目中都使用(这 800 个文件 来自另一个 3rd 方软件)。我尝试使用 AutoIt 实现组合生成, 技术上方法 1)生成 24,517,914,624 个条目,在生成后立即对每个条目中的编号进行排序,并丢弃其中包含重复编号的条目。 这种方法需要永远运行,因为它涉及数十亿个条目进行测试/排序,并且其数组大小远高于 AutoIt 的数组大小限制(1600 万)。因此方法 1) 可以被丢弃, 它只适用于(最多)5个数字组合(例如1,3,7,14,23)。

对于方法 2),我尝试了 2 种变体:

i) 将每个步骤中的结果存储在临时数组中,并使用 AutoIt 的 _ArrayUnique 函数删除重复条目。这也需要永远运行!

ii) 我没有将结果存储在 temp 数组中,而是使用 SQLite,即将每个步骤中生成的组合放入 SQLite 中的单行表中,使用 PRIMARY KEY UNIQUE 创建表/行然后我选择排回 AutoIt 进行进一步处理。

变体 ii) 最终起作用,处理 1 个文件需要 1 小时 20 分钟(我有 800 个这样的文件)

现在我打算在VC++(VS 2017)中实现组合生成,我有以下问题:

1) 除了“蛮力”和“逐步”之外,从性能的角度来看,还有其他方法/算法可以从多个数组/向量生成唯一组合吗?

2) 要对每个条目中的数字进行排序并检查每个条目中的重复数字,我认为 std::sort, std::search/std::find 会完成这项工作,因为将有数百万个条目需要检查,从性能的角度来看,还有其他选择吗?

3) 要删除重复条目(统一组合列表,即获取唯一组合),我应该使用 std::unique 还是仍然依赖 SQLite ?因为数组的大小可能大到 30~40 百万,在 std::sort 和 std::unique 或 SQLite 的 SELECT 之后缩小到 1000 万(不知道从性能角度来看哪个实现更好)

4) 任何现成的 LIB 都可以轻松完成任务?

非常感谢。

注册表

林志峰

【问题讨论】:

    标签: c++ arrays vector unique combinations


    【解决方案1】:

    只要找出 std::set,它的排序/独特功能就可以满足我的需要。我用它实现了逐步方法,程序运行得像飞一样。只是它在第 6 行之后很容易耗尽内存,所以我将它与 SQLite 结合起来,即在处理 6 行之后,我丢弃 std::set 并将组合结果存储在 SQLite 表中(具有 PRIMARY KEY UNIQUE 的单行表)。这可能不是一个完美的解决方案,但可行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-17
      相关资源
      最近更新 更多