我有46个项目的清单。每个都有一个与之相关的数字。我希望将这些物品配对成23对。我想评估每组的功能。我该如何生成这样的一套?
我可以使用itertools中的组合函数来生成所有的2-ples,但是我没有看到如何生成23对的所有组。
我该怎么做或是否有我可以参考的示例代码?
答案 0 :(得分:1)
>>> 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]
编辑:
对于对的powerset,我们首先以相同的方式创建对。对于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)
答案 1 :(得分:0)
首先,从列表中获取所有对的自然方法是:
>>> 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 )。
<编辑:编辑:人们批评O(N!),但是所需的解决方案增长为O(N!)这个问题要求将N个元素的列表(假设所有元素的大多数一般情况都是不同的)分成一组(N / 2)对,不仅要做一次,而且要生成 all 强>这些配对的集合。这个答案是唯一一个这样做的答案。是的,它指数速度慢,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)!&amp; 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的解决方案!排列,排序和丢弃重复是次优的。