【问题标题】:How to combine large list of lists (of lists again) under certain condition如何在特定条件下合并大列表(再次列表)
【发布时间】:2019-12-10 07:04:02
【问题描述】:

我正在尝试解决来自生物学领域的问题,我必须将每个大元素的局部次优解决方案结合起来,以使每个子粒子都是独一无二的。问题是可能性可以扩展到 +4.000 局部次优解决方案和 +30.000 元素。笛卡尔积不是一个选项,因为组合列表是一个 n*m*p*... 问题,如果没有超越 itertools 的算法,这是不可能的。

一般架构是:

[
  [ [a,b,c],[d,e,a],[f], ...],
  [ [f,e,t],[a,b,t],[q], ...],
  [ [a,e,f],[],[p], ... up to 4.000],
  ... up to 30.000
]

[ [a,b,c],[d,e,a],[f],.....], -> 一组用于 elem 的次优解决方案。 #1

我想尽快找到

  • 第一个:一个解决方案,这意味着每个元素的一个次优解决方案的组合(可能包括空白列表),这样就不会有重复项。例如 [[a,b,c],[f,e,t][p]]。

  • 第二:所有兼容的解决方案。

我知道这是一个悬而未决的问题,但是我需要一些指导或通用算法来解决这个问题,如果我有什么要开始的话,我可以进一步调查。

我在实验室的其余工作中使用 python,但是我对其他语言持开放态度。

我们可以从一个基本的求解器开始,该求解器在总的次优和列表数量方面处理较少的可能性。

最好的。

编辑 1

一个非常简短真实的例子:

[[[1,2,3][1,2,4],[1,2,5],[5,8]],
[[1,3][7,8],[6,1]],
[[]],
[[9,10][7,5],[6,9],[6,10]]]

最佳解决方案(从第 # 行开始):

#1 [1,2,3]
#2 [7,8]
#3 [9,10]

Output: [[1,2,3],[7,8],[9,10]]

可以看这里https://pastebin.com/qq4k2FdW

【问题讨论】:

  • 嗨,欢迎来到 SO。您能否提供一些小样本输入、预期输出以及您的方法中可重现的代码示例(如果有)?
  • 所以一行应该没有重复值?
  • LazyCoder,感谢您的快速回答。现在在答案正文中找到一个示例,也是一个最佳结果。
  • Basilisk,所需的解决方案在每个“大”列表中都有一个元素,在这些列表之间,条件是所有元素都是唯一的。
  • 一个元素是指一行(列表或数组)还是数字?抱歉,我没有看到这里的模式,这些列表之间的条件是元素是唯一的吗?为什么你不使用 6 ?这是独一无二的

标签: python algorithm list cartesian-product branch-and-bound


【解决方案1】:

这里有几个算法。您可以非常简单地使用 itertools 对所有可能的组合进行暴力搜索:

from itertools import product, chain

def get_compatible_solutions(subsolutions):
    for sol in product(*subsolutions):
        if len(set(chain.from_iterable(sol))) == sum(map(len, sol)):
            yield sol

# Test
example = [
    [[1, 2, 3], [1, 2, 4], [1, 2, 5], [5, 8]],
    [[1, 3], [7, 8], [6, 1]],
    [[]],
    [[9, 10], [7, 5], [6, 9], [6, 10]]
]

# Get one solution
print(next(get_compatible_solutions(example)))
# ([1, 2, 3], [7, 8], [], [9, 10])

# Get all solutions
print(*get_compatible_solutions(example), sep='\n')
# ([1, 2, 3], [7, 8], [], [9, 10])
# ([1, 2, 3], [7, 8], [], [6, 9])
# ([1, 2, 3], [7, 8], [], [6, 10])
# ([1, 2, 4], [7, 8], [], [9, 10])
# ([1, 2, 4], [7, 8], [], [6, 9])
# ([1, 2, 4], [7, 8], [], [6, 10])
# ([1, 2, 5], [7, 8], [], [9, 10])
# ([1, 2, 5], [7, 8], [], [6, 9])
# ([1, 2, 5], [7, 8], [], [6, 10])
# ([5, 8], [1, 3], [], [9, 10])
# ([5, 8], [1, 3], [], [6, 9])
# ([5, 8], [1, 3], [], [6, 10])
# ([5, 8], [6, 1], [], [9, 10])

另一种可能性是一次进行一行递归搜索。这将探索比笛卡尔积更少的候选解决方案,因为一旦从搜索路径中排除次优解决方案,就不会处理包括它在内的任何组合。

def get_compatible_solutions(subsolutions):
    current = [None] * len(subsolutions)
    seen = set()
    yield from _get_compatible_solutions_rec(subsolutions, current, 0, seen)

def _get_compatible_solutions_rec(subsolutions, current, i, seen):
    if i >= len(subsolutions):
        yield tuple(current)
    else:
        for subsol in subsolutions[i]:
            if any(s in seen for s in subsol):
                continue
            seen.update(subsol)
            current[i] = subsol
            yield from _get_compatible_solutions_rec(subsolutions, current, i + 1, seen)
            seen.difference_update(subsol)

【讨论】:

  • 我现在无法测试代码,但是我正在使用蛮力解决方案,并且不能像 n*m 那样工作,所以很快就有数十亿种可能性。你认为递归的可以面对这个问题吗?非常感谢您的回答。
  • @HardinSalvor 我运行了一个合成示例,每个元素最多有 5 个次优解,每个次优解在 [0, 99] 中最多包含 5 个不同的整数,总共有 10 个项目。兼容解的数量为 675,601,第一个算法探索了 9,765,625 个候选完整解,耗时 15.3s,而第二个算法探索了 1,666,535 个候选部分解,耗时 1.6s。有一个重要的加速,但不是几个数量级。
  • @HardinSalvor 不同次优解元素数量的通常范围是多少(即abc...的数量)。
  • 我在少于十亿种可能性的情况下测试并快速运行。然而,我们的案例在那个疯狂的范围内(这就是为什么我不知道组合是否是答案)。每行的实际范围通常扩展到数千个次优解决方案。
猜你喜欢
  • 2014-01-26
  • 2022-12-07
  • 2020-06-10
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多