Python 如何在一定条件下组合大列表(再次列表)
我试图解决一个来自生物学领域的问题,在这个领域中,我必须结合每个大元素的局部次优解,这样每个子粒子都是唯一的。问题是,可能性可能会扩大到+4.000个局部次优解决方案,以及+30.000个元素。笛卡尔乘积不是一个选项,因为组合列表是一个Python 如何在一定条件下组合大列表(再次列表),python,algorithm,list,cartesian-product,branch-and-bound,Python,Algorithm,List,Cartesian Product,Branch And Bound,我试图解决一个来自生物学领域的问题,在这个领域中,我必须结合每个大元素的局部次优解,这样每个子粒子都是唯一的。问题是,可能性可能会扩大到+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], .
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],…],一组元素的次优解#一,
我想尽快找到
- 首先:一个解决方案,这意味着每个元素的一个次优解决方案的组合(可以包括空白列表),这样就不会有重复。例如[[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]]]
最佳解决方案(来自第#行):
可以在这里看到这里有一些算法。您可以使用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)
这里有几个算法。您可以使用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)
嗨,欢迎来到苏。请您提供一些小样本输入、预期输出以及您的方法中的可复制代码样本(如果有的话)?这样一行应该没有重复值?LazyCoder,谢谢您的快速回答。现在在答案的正文中找到一个例子,也是一个最佳结果。Basilisk,所需的解决方案从每个“大”列表中有一个元素,这些列表之间的条件是所有元素都是唯一的。一个元素是指一行(列表或数组)或一个数字?我看不到这里的模式对不起,这些列表之间的关系如何?条件是元素是唯一的?你为什么不使用6?是uniqueHi,欢迎来到SO。请您提供一些小样本输入、预期输出以及您的方法中的可复制代码样本(如果有的话)?这样一行应该没有重复值?LazyCoder,谢谢您的快速回答。现在在答案的正文中找到一个例子,也是一个最佳结果。Basilisk,所需的解决方案从每个“大”列表中有一个元素,这些列表之间的条件是所有元素都是唯一的。一个元素是指一行(列表或数组)或一个数字?我看不到这里的模式对不起,这些列表之间的关系如何?条件是元素是唯一的?你为什么不使用6?这是唯一的,我现在无法测试代码,但暴力解决方案是我正在使用的解决方案,没有像n*m那样工作,所以很快就有了数十亿种可能性。你认为递归的一个可以面对这个问题吗?非常感谢您的回答。@HardinSalvor我运行了一个合成示例,每个元素最多有5个次优解,每个次优解在[0,99]中最多包含5个不同的整数,总共有10项。兼容解的数量为675601,第一个算法探索了9765625个候选完整解,耗时15.3秒,而第二个算法探索了1666535个候选部分解,耗时1.6秒。有一个重要的加速,但不是几个数量级。@HardinSalvor不同次优解决方案元素(即a
,b
,c
…)的数量的通常范围是多少。我在可能性小于10亿的情况下进行了测试并快速运行。然而,我们的情况是在那个疯狂的范围内(这就是为什么我不知道组合是否是答案)。每行的实际范围通常会扩展到数千个次优解决方案。我现在无法测试代码,但暴力解决方案是我正在使用的解决方案,并且没有像n*m那样工作,因此很快就有数十亿种可能性。你认为递归的一个可以面对这个问题吗?非常感谢您的回答。@HardinSalvor我运行了一个合成示例,每个元素最多有5个次优解,每个次优解在[0,99]中最多包含5个不同的整数,总共有10项。兼容解的数量为675601,第一个算法探索了9765625个候选完整解,耗时15.3秒,而第二个算法探索了1666535个候选部分解,耗时1.6秒。有一个重要的加速,但不是几个数量级。@HardinSalvor不同次优解决方案元素(即a
,b
,c
…)的数量的通常范围是多少。我在可能性小于10亿的情况下进行了测试并快速运行。然而,我们的情况是在那个疯狂的范围内(这就是为什么我不知道组合是否是答案)。每行的实际范围通常扩展到数千个次优解。