我想在给定大小为n
的数组的情况下生成所有可能的 4元组对的列表。 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), (3,4)], [(2,3), (4,5)], [(2,4), (3,5)], [(2,5), (3,4)]
我目前的做法是使用python中的itertools
并浏览itertools.combinations
返回的所有元素,执行2次循环并查找不共享单个元素的2对然后使用那个元素。
为了在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
此方法正在执行其工作,但由于2个循环而效率低,并且仅适用于给定时间范围内的小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提供答案,因为这是解决此问题的最简单,最简单的答案。
答案 0 :(得分:3)
你通过生成所有组合对执行大量不必要的工作,然后丢弃几乎所有组合,因为它们包含共同元素。
以下通过首先获取四个数字的所有子集(在您的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)]
),因此会产生两倍于您期望的元素。
然而,删除重复项是微不足道的。这留给读者练习。
答案 1 :(得分:0)
您可以使用更快的排列和拆分:
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
注意:如果数组的长度不是大小的倍数,则此解决方案可以工作,但会产生重复。
答案 2 :(得分:0)
我会这样做:
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)]]
答案 3 :(得分:0)
这里有代码来生成MSeifert的yield语句:)(并且它只产生35个,这意味着没有重复:)
static void Main(string[] args)
{
var t1 = new ActionBlock<int>(async i =>
{
await Task.Delay(2000);
Trace.TraceInformation($"target 1 | Thread {System.Threading.Thread.CurrentThread.ManagedThreadId} | message {i}");
}, new ExecutionDataflowBlockOptions { BoundedCapacity = 5 });
var t2 = new ActionBlock<int>(async i =>
{
await Task.Delay(1000);
Trace.TraceInformation($"target 2 | Thread {System.Threading.Thread.CurrentThread.ManagedThreadId} | message {i}");
}, new ExecutionDataflowBlockOptions { BoundedCapacity = 5 });
var t3 = new ActionBlock<int>(async i =>
{
await Task.Delay(100);
Trace.TraceInformation($"target 3 | Thread {System.Threading.Thread.CurrentThread.ManagedThreadId} | message {i}");
if (i > 5)
throw new Exception("Too big number");
}, new ExecutionDataflowBlockOptions { BoundedCapacity = 5 });
var targets = new [] { t1, t2, t3};
var broadcaster = new ActionBlock<int>(
async item =>
{
var processingTasks = targets.Select(async t =>
{
try
{
await t.SendAsync(item);
}
catch
{
Trace.TraceInformation("handled in select"); // never goes here
}
});
try
{
await Task.WhenAll(processingTasks);
}
catch
{
Trace.TraceInformation("handled"); // never goes here
}
});
for (var i = 1; i <= 10; i++)
broadcaster.Post(i);
}