我有一个包含 46 个项目的列表。每个都有一个与之关联的数字。我想将这些物品配对成一组 23 对。我想评估每个集合的函数。如何生成这样的集合?
我可以使用 itertools 中的组合函数来生成所有 2-ples,但我不知道如何生成所有 23 对的集合。
我该怎么做或者有我可以参考的示例代码?
我有一个包含 46 个项目的列表。每个都有一个与之关联的数字。我想将这些物品配对成一组 23 对。我想评估每个集合的函数。如何生成这样的集合?
我可以使用 itertools 中的组合函数来生成所有 2-ples,但我不知道如何生成所有 23 对的集合。
我该怎么做或者有我可以参考的示例代码?
>>> L=range(46)
>>> def f(x, y): #for example
... return x * y
...
>>> [f(x, y) for x, y in zip(*[iter(L)] * 2)]
[0, 6, 20, 42, 72, 110, 156, 210, 272, 342, 420, 506, 600, 702, 812, 930, 1056, 1190, 1332, 1482, 1640, 1806, 1980]
编辑:
对于对的幂集,我们首先以相同的方式创建对。对于 Python3 使用range
代替xrange
S = zip(*[iter(L)] * 2) # set of 23 pairs
[{j for i, j in enumerate(S) if (1<<i)&k} for k in xrange(1<<len(S))]
这将是一个相当大的列表,您可能想要使用生成器表达式
for item in ({j for i, j in enumerate(S) if (1<<i)&k} for k in xrange(1<<len(S))):
func(item)
首先,从列表中获取所有对的自然方法是:
>>> N = 10
>>> input_list = range(N)
>>> [(a,b) for a, b in zip(input_list[::2], input_list[1::2])]
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
如果你想生成所有这样的对,我会做类似的事情(这就是我在下面所说的案例 1):
>>> set_of_all_pairs = set()
>>> input_list = range(N)
>>> import itertools
>>> for perm in itertools.permutations(input_list):
pairs = tuple([(a,b) for a, b in zip(perm[::2], perm[1::2])])
set_of_all_pairs.add(pairs)
假设这将区分对中的顺序(例如,(1,4)不同于(4,1)),并认为对的顺序有意义。因此,如果您在添加到集合之前对对和对集合进行排序:
>>> set_of_all_pairs = set()
>>> input_list = range(N)
>>> import itertools
>>> for perm in itertools.permutations(input_list):
pairs = sorted([tuple(sorted((a,b))) for a, b in zip(perm[::2], perm[1::2])])
set_of_all_pairs.add(tuple(pairs))
这不是一个有效的算法(我称之为下面的案例 3),但对于 N 的小值,它会起作用。
对于 N=6,使用排序方法。
set([((0, 4), (1, 3), (2, 5)),
((0, 4), (1, 5), (2, 3)),
((0, 1), (2, 3), (4, 5)),
((0, 3), (1, 5), (2, 4)),
((0, 2), (1, 5), (3, 4)),
((0, 4), (1, 2), (3, 5)),
((0, 3), (1, 4), (2, 5)),
((0, 1), (2, 4), (3, 5)),
((0, 5), (1, 4), (2, 3)),
((0, 5), (1, 2), (3, 4)),
((0, 2), (1, 3), (4, 5)),
((0, 3), (1, 2), (4, 5)),
((0, 2), (1, 4), (3, 5)),
((0, 1), (2, 5), (3, 4)),
((0, 5), (1, 3), (2, 4))])
请注意,解空间呈指数级增长;(例如,对于 N=6,其 15;N=8,其 105;N=10,其 945,对于 N=46,将为 25373791335626257947657609375 ~ 2.5 x 10 28)。
该问题要求将 N 个元素的列表(假设所有元素都不同的最一般情况)分解为一组 (N/2) 对,并且不仅执行一次,而且生成所有这些对的集合。这个答案是唯一这样做的。是的,它的速度呈指数级增长,并且对于 N=46 完全不可行。这就是我使用 N=10 的原因。
对这个问题有三种合理的解释:
情况 1:在元组中的一对内部的排序(例如,函数参数不是对称的)和一组对中的对的顺序也很重要,那么我们将有 N!在我们的答案中配对数字的方法。在这种情况下,这意味着 (0,1) 和 (1,0) 对都被认为是不同的,对于 N=4 的情况,我们认为这对{(0,1), (2,3)}
与 不同{(2,3),(0,1)}
。
案例 2:排序在一对中很重要,但在一组配对中顺序无关紧要。这意味着我们将 (0,1) 和 (1,0) 视为不同的对,但考虑(对于 N=4 的情况)该集合{(0,1),(2,3)}
与该集合相同{(2,3), (0,1)}
并且不需要同时考虑两者。在这种情况下,我们将有 N!/(N/2)! 配对,因为任何给定的集合都有(N / 2)!不同的顺序。(我没有在上面明确给出这个;只是停止对元组进行排序)。
案例 3:在一对和一组配对中排序都无关紧要。这意味着我们将 (0,1) 和 (1,0) 视为同一对(函数参数是对称的),因此我们将有 N!/( (N/2)! & 2^(N/2) ) 个集合对 ( factorial(N)/(factorial(N/2)*2**(N/2))
)。每个组合中的每个 (N/2) 对将有两个起作用的内部排序。
因此,根据问题的表述方式,我们应该有:
Case 1 | Case 2 | Case 3
----------------------------------------------
N N! | N!/(N/2)! | N!/((N/2)! 2^(N/2))
6 720 | 120 | 15
8 40320 | 1680 | 105
10 3628800 | 30240 | 945
46 5.5x10^57 | 2.1x10^35 | 2x10^28
请注意,我的算法将遍历所有排列,因此对于案例 3(由于排序)实际上会比案例 1 运行得更慢,即使案例 3 的更好算法可能会快得多。但是,我的答案在渐近符号中仍然是最佳的,因为即使案例 3 在其渐近运行时间中也是阶乘,并且完全无法求解 N~46。如果您必须在案例 3 的可行性极限 (N~16) 下做一个问题大小(例如,需要生成 518918400.0 对),那么这种迭代所有 N! 排列、排序和丢弃重复项是次优的。