Python 从n个元素生成所有4元组对
我想生成一个所有可能的4元组对的列表,给定一个大小为Python 从n个元素生成所有4元组对,python,algorithm,combinatorics,Python,Algorithm,Combinatorics,我想生成一个所有可能的4元组对的列表,给定一个大小为n的数组n至少为8,因此始终可以找到至少1对 作为一个有助于理解问题的示例,我使用了问题的一个较小版本,2元组对给定一个大小为5的数组。2元组对的预期结果将产生15项(元组是有序的,没有重复): [(1,2)、(3,4)]、[(1,2)、(3,5)]、[(1,2)、(4,5)]、[(1,3)、(2,4)]、[(1,3)、(2,5)]、[(1,3)、(4,5)]、[(1,4)、(2,3)]、[(1,4)、(2,5)]、[(1,4)、(3,5)]、
n
的数组n
至少为8,因此始终可以找到至少1对
作为一个有助于理解问题的示例,我使用了问题的一个较小版本,2元组对给定一个大小为5
的数组。2元组对的预期结果将产生15项(元组是有序的,没有重复):
[(1,2)、(3,4)]、[(1,2)、(3,5)]、[(1,2)、(4,5)]、[(1,3)、(2,4)]、[(1,3)、(2,5)]、[(1,3)、(4,5)]、[(1,4)、(2,3)]、[(1,4)、(2,5)]、[(1,4)、(3,5)]、[(1,5)、(2,3)]、[(1,5)、(2,4)]、[(1,5]、[(1,5]、[(1,5)、(3,4)]、[(2,4]、[(2,5)]、[(2,5)]、[(2,5)]、[(2,5)]、[(2,5)]、[(2,5)]、[(2,5)]、[(2,5)]
我目前的做法是使用python中的itertools
,检查itertools.compositions返回的所有元素,执行两个循环,找到两个不共享单个元素的对,然后使用该元素
为了用python代码表达这一点,我准备了一个小片段:
arr = list(range(30)) # example list
comb = list(itertools.combinations(range(0, len(arr)), 4))
for c1 in comb:
for c2 in comb: # go through all possible pairs
if len([val for val in c1 if val in c2]) == 0: # intersection of both sets results in 0, so they don't share an element
... # do something and check for duplicates
此方法正在发挥作用,但由于存在两个循环,效率低下,并且在给定的时间范围内仅适用于较小的n
。这样做能更有效率吗
更新:在回答了一些问题后,我评估了这些建议。对于我的具体情况,最好的方法是MSeifert(现已删除)答案提供的(扩展)算法,该算法执行速度最快:
def generate_four_pairs(n):
valids = range(0, n)
for x00, x01, x02, x03, x10, x11, x12, x13 in itertools.combinations(valids, 8):
yield [x00, x01, x02, x03], [x10, x11, x12, x13]
yield [x00, x01, x02, x10], [x03, x11, x12, x13]
yield [x00, x01, x02, x11], [x03, x10, x12, x13]
yield [x00, x01, x02, x12], [x03, x10, x11, x13]
yield [x00, x01, x02, x13], [x03, x10, x11, x12]
yield [x00, x01, x03, x10], [x02, x11, x12, x13]
yield [x00, x01, x03, x11], [x02, x10, x12, x13]
yield [x00, x01, x03, x12], [x02, x10, x11, x13]
yield [x00, x01, x03, x13], [x02, x10, x11, x12]
yield [x00, x01, x10, x11], [x02, x03, x12, x13]
yield [x00, x01, x10, x12], [x02, x03, x11, x13]
yield [x00, x01, x10, x13], [x02, x03, x11, x12]
yield [x00, x01, x11, x12], [x02, x03, x10, x13]
yield [x00, x01, x11, x13], [x02, x03, x10, x12]
yield [x00, x01, x12, x13], [x02, x03, x10, x11]
yield [x00, x02, x03, x10], [x01, x11, x12, x13]
yield [x00, x02, x03, x11], [x01, x10, x12, x13]
yield [x00, x02, x03, x12], [x01, x10, x11, x13]
yield [x00, x02, x03, x13], [x01, x10, x11, x12]
yield [x00, x02, x10, x11], [x01, x03, x12, x13]
yield [x00, x02, x10, x12], [x01, x03, x11, x13]
yield [x00, x02, x10, x13], [x01, x03, x11, x12]
yield [x00, x02, x11, x12], [x01, x03, x10, x13]
yield [x00, x02, x11, x13], [x01, x03, x10, x12]
yield [x00, x02, x12, x13], [x01, x03, x10, x11]
yield [x00, x03, x10, x11], [x01, x02, x12, x13]
yield [x00, x03, x10, x12], [x01, x02, x11, x13]
yield [x00, x03, x10, x13], [x01, x02, x11, x12]
yield [x00, x03, x11, x12], [x01, x02, x10, x13]
yield [x00, x03, x11, x13], [x01, x02, x10, x12]
yield [x00, x03, x12, x13], [x01, x02, x10, x11]
yield [x00, x10, x11, x12], [x01, x02, x03, x13]
yield [x00, x10, x11, x13], [x01, x02, x03, x12]
yield [x00, x10, x12, x13], [x01, x02, x03, x11]
yield [x00, x11, x12, x13], [x01, x02, x03, x10]
yield [x01, x02, x03, x00], [x10, x11, x12, x13]
yield [x01, x02, x03, x10], [x00, x11, x12, x13]
yield [x01, x02, x03, x11], [x00, x10, x12, x13]
yield [x01, x02, x03, x12], [x00, x10, x11, x13]
yield [x01, x02, x03, x13], [x00, x10, x11, x12]
yield [x01, x02, x10, x00], [x03, x11, x12, x13]
yield [x01, x02, x10, x11], [x00, x03, x12, x13]
yield [x01, x02, x10, x12], [x00, x03, x11, x13]
yield [x01, x02, x10, x13], [x00, x03, x11, x12]
yield [x01, x02, x11, x00], [x03, x10, x12, x13]
yield [x01, x02, x11, x12], [x00, x03, x10, x13]
yield [x01, x02, x11, x13], [x00, x03, x10, x12]
yield [x01, x02, x12, x00], [x03, x10, x11, x13]
yield [x01, x02, x12, x13], [x00, x03, x10, x11]
yield [x01, x02, x13, x00], [x03, x10, x11, x12]
yield [x01, x03, x10, x00], [x02, x11, x12, x13]
yield [x01, x03, x10, x11], [x00, x02, x12, x13]
yield [x01, x03, x10, x12], [x00, x02, x11, x13]
yield [x01, x03, x10, x13], [x00, x02, x11, x12]
yield [x01, x03, x11, x00], [x02, x10, x12, x13]
yield [x01, x03, x11, x12], [x00, x02, x10, x13]
yield [x01, x03, x11, x13], [x00, x02, x10, x12]
yield [x01, x03, x12, x00], [x02, x10, x11, x13]
yield [x01, x03, x12, x13], [x00, x02, x10, x11]
yield [x01, x03, x13, x00], [x02, x10, x11, x12]
yield [x01, x10, x11, x00], [x02, x03, x12, x13]
yield [x01, x10, x11, x12], [x00, x02, x03, x13]
yield [x01, x10, x11, x13], [x00, x02, x03, x12]
yield [x01, x10, x12, x00], [x02, x03, x11, x13]
yield [x01, x10, x12, x13], [x00, x02, x03, x11]
yield [x01, x10, x13, x00], [x02, x03, x11, x12]
yield [x01, x11, x12, x00], [x02, x03, x10, x13]
yield [x01, x11, x12, x13], [x00, x02, x03, x10]
yield [x01, x11, x13, x00], [x02, x03, x10, x12]
yield [x01, x12, x13, x00], [x02, x03, x10, x11]
对于一般方法,我建议使用NPE提供的答案,因为这是这个问题最短、最容易阅读的答案。生成所有组合对,然后丢弃几乎所有组合,因为它们包含公共元素,这会做很多不必要的工作
下面通过首先获取四个数字的所有子集(在2元组示例中),然后将每个子集拆分为所有可能的对来解决此问题:
import itertools
def gen_pairs(n, m):
for both_halves in itertools.combinations(xrange(1, n + 1), 2 * m):
for first_half in itertools.combinations(both_halves, m):
second_half = tuple(sorted(set(both_halves) - set(first_half)))
yield [first_half, second_half]
print sorted(gen_pairs(5, 2))
请注意,这并不能消除重复项(例如,[(4,5)(2,3)]
vs[(2,3)、(4,5)]
),因此产生的元素数量是预期的两倍
然而,删除重复项并不重要。这是留给读者的练习。您可以使用排列和拆分,这可能会更快:
array = ...
size = 4
c = itertools.permutations(array)
for t in c:
a = []
for i in range(0, len(t), size):
if i + size <= len(t):
a.append(t[i:i+size])
yield a
array=。。。
尺寸=4
c=itertools.排列(数组)
对于c中的t:
a=[]
对于范围内的i(0,长度(t),尺寸):
如果i+size我会:
from itertools import combinations
sample = range(1,6)
x1 = [subset for subset in combinations(sample,2)] #getting the set of tuples
x2 = [list(subset) for subset in combinations(x1,2)] #getting the pair of tuples
x3 = [x for x in x2 if (set(x[0]) & set(x[1]) == set())] #finally filtering the tuples with no intersection
输出:
[[(1, 2), (3, 4)],
[(1, 2), (3, 5)],
[(1, 2), (4, 5)],
[(1, 3), (2, 4)],
[(1, 3), (2, 5)],
[(1, 3), (4, 5)],
[(1, 4), (2, 3)],
[(1, 4), (2, 5)],
[(1, 4), (3, 5)],
[(1, 5), (2, 3)],
[(1, 5), (2, 4)],
[(1, 5), (3, 4)],
[(2, 3), (4, 5)],
[(2, 4), (3, 5)],
[(2, 5), (3, 4)]]
下面是生成MSeifert的yield语句的代码:)(它只生成其中的35条语句,这意味着没有重复的语句:)
def g(L,n,k,A,B):
如果len(A)==k:
返回[[tuple(A),tuple([L[i]表示x范围内的i(0,n+1)]+B)]]
elif len(B)=k:
返回[[tuple([L[i]表示xrange(0,n+1)中的i)]+A,tuple(B)]]
返回g(L,n-1,k,A[L[n]]+B[0:])+g(L,n-1,k[L[n]]+A[0:],B)
def f(L):
断言(len(L)>3,len(L)%2==0)
返回g(L,len(L)-2,len(L)/2,[],[L[-1]]
对于f中的i(['x00','x01','x02','x03','x10','x11','x12','x13']):
印刷品(一)
什么是arr
,您确定itertools
解决方案真的有效吗?为什么是15个元素而不是30个?例如,[(4,5)(2,3)]
有什么问题?@MSeifert,它相当于列表中已有的[(2,3)、(4,5)]
。“元组是有序的,没有重复。”但是所提供的itertools
解决方案实际上给出了[(4,5),(2,3)]
如果itertools.compositions(范围(0,len(arr)),4)
被itertools.compositions(范围(1,6),2)
所取代,这就是为什么我想知道该解决方案是否有效或正确。如果假定len(arr)
为5
,那么目前肯定不会。是的,上述解决方案也存在重复。它们在最后被过滤,因为我不知道有什么比在最后过滤它们更容易的解决方案。很抱歉,这一误解仍然存在一个问题,即arr
未定义,并且组合中的4
似乎是错误的,因为您需要2个2元组。但是你的方法会给出2个4元组。很好的解决方案!读者提示:仅当上半部分的第一个元素小于下半部分的第一个元素时,才调用yield