all permutations from 2 lists but with a condition on the amount of elements(来自2个列表的所有排列,但以元素数量为条件)
问题描述
在Python中我有:
我正在尝试构建从列表a
或b
中选择的10个字符的所有可能排列,其中将包括任何排列,其中至少3个元素来自a
,至少3个元素来自b
。这些元素可以重复,因为它们是从列表中选择的。
例如,有效排列:wa85ff3d56
、333aaaaaaa
、a33333aa33
做到这一点最有效的方法是什么? PS:是的,我知道,答案将是非常大的。这是意料之中的。它不会存储在内存中,而是会在实时计算中进行流式处理和使用。
目前,我生成所有可能的组合,然后对它们进行置换。然而,计算几乎肯定需要几个月的时间。我有这样一段代码,它确实有效,但显然不是最有效的方式。例如,对于列表a
中的3个和列表b
中的7个,它生成2.864429568e+14
排列。考虑到我必须这样做5次(3,7), (4,6), (5,5), (6,4), (7,3)
,我总共得到了1.432214784e+15
个排列。相比之下,如果没有限制,就会有36^10 = 3.65615844e+15
。因此,此方法将删除几乎一半的可能排列。
推荐答案
我想在这里尝试编写一个通用的答案,希望将来有一个很好的规范目标来处理重复问题。
使用itertools
结合使用Python中的基本知识
重新排序和替换(重复)
了解itertools
提供的各种combinatoric iterators如何工作以及它们之间的区别非常重要。
让我们考虑一个简单的候选集合A = [1, 2, 3, 4]
,我们要从其中抽取包含三个元素的组合(如提问者通常所说)。
itertools.combinations
选择时不重新排序(即,每个输出值将以与输入中相同的顺序显示),并且不重复结果值。因此,这只产生4个结果:
itertools.permutations
表示结果可以以任何顺序出现,即输入的给定子集将以不同的顺序在输出中多次出现。
这四个combinations
以六个顺序显示,总共有24个结果。
itertools.combinations_with_replacement
选择而不重新排序,但允许多次选择输入中的元素:
combinations
。在一般情况下,计算结果并非易事。
如果要在输出结果中允许重复和重新排序,可以使用itertools.product
:
简单地说,我们每三次从四个元素中自由选择一次,得到4*4*4=64个结果。
itertools.product
实现了所谓的Cartesian product。通常,它从多个指定的序列中各提取一个元素。但是,使用替换生成&置换等同于多次从同一序列中提取一个元素,因此提供了repeat
关键字作为此操作的便捷快捷方式-因此您不必多次指定序列。我的意思是,你可以写itertools.product(*[A]*3)
,但那很难看。
候选集中的重复项怎么办?
这与OP提出的问题无关;但为了完整性,重要的是要了解这些函数都不关心候选集合的元素是否相等,甚至相同:
如何实现约束?
最简单的方法是生成一个包含性结果(在OP的例子中,通过将a
和b
候选连接在一起,并生成其中10个候选的product
),并过滤掉不符合要求的内容。然而,这是低效的,而且可能很难看(我们需要分析输出元组以确定其元素是否满足条件-在OP的例子中,它们是从a
还是从b
提取的。如果您确实想采用这样的方法,我通常建议您编写一个生成器函数:
或者在足够简单的情况下,生成器表达式:
通常最好尝试将问题分解成小块,然后将结果放在一起。例如,文档中有一个计算power sets的配方,它简单地将0元素、1元素等组合的结果链接到所有元素。(另一种方法是找到N个布尔值的笛卡尔乘积,每个布尔值表示是否包括给定的元素,然后将它们转换为子集。)
在我们的例子中,我们可以分别找到每个a
元素计数的结果。让我们考虑一下每个列表中有5个元素的情况;应该清楚如何泛化并组合结果(提示:使用itertools.chain.from_iterable
,如文档中的powerset
配方所示)。
疑难情况:分区和位置选择
我想在这里展示一种高级技术,以解决从a
中选择5个元素和从b
中选择5个元素并将它们混合的问题。这个想法很简单,我们从所有可能的位置(即索引到10个元素的序列)中选择a将去的位置,并为每个位置生成相应的输出结果。这些职位是没有替代的组合(你知道为什么吗?)可能的索引值。
因此,如下所示:
选择位置的技巧对于解决partitioning问题也很有用。这个想法很简单,你选择分区的位置(对于N个元素,通常有N-1个位置来放置它们),作为组合-或者有(如果允许零大小的分区),或者没有(否则)替换。这篇关于来自2个列表的所有排列,但以元素数量为条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!