生成相邻的对排列,其中对的每一侧只能使用一次

时间:2013-06-07 19:01:04

标签: python itertools

我有相邻的配对(1:2)(2:3)(3:4)(4:5)(7:8).. ..

我想识别所有的排列,但是这一对的每一面只能在一个排列中使用一次,我想知道未使用的值。


(1:2)(3:4)(7:8)未使用:5
(2:3)(4:5)(7:8)未使用:1
(1:2)(4:5)(7:8)未使用:3

提前感谢您的建议和想法。

我正在使用的一些实际配对列表是

list1 = [(427,3434),(614,2445),(840,614),(910,3939),(1065,4314),(1347,2616),(2445,427),(2616) ,3901),(2749,1065),(3403,910),(3434,1347),(3659,1411),(3901,3684),(3939,2638),(4203,3403),(4314,840) )]

list2 = [(1218,134),(3344,1218),(3683,3344),(2055,3683),(2709,2055)]

1 个答案:

答案 0 :(得分:0)

这是一个快速的程序,我一起解决这个问题。这可能不是最有效的方法,但它完成了工作。

l = [(1,2),(2,3),(3,4),(4,5)]  # replace with whatever your full list is
import itertools
for perm in itertools.permutations(l,len(l) / 2):
    pair_list = []
    for pair in perm:
        if pair[0] in itertools.chain(*(i for i in pair_list)) \
        or pair[1] in itertools.chain(*(i for i in pair_list)):
            break
        pair_list.append(pair)
    if len(pair_list) == len(l) / 2:
        unused = []
        for n in itertools.chain(*(i for i in l)):
            if n not in itertools.chain(*(i for i in pair_list)) and n not in unused:
                unused.append(n)
        print pair_list,'unused:',unused

此外,您确定要确定所有排列吗?为了获得准确的输出,我需要将itertools.permutations替换为itertools.combinations

以下是我使用itertools.permutations获得的输出:

[(1, 2), (3, 4)] unused: [5]
[(1, 2), (4, 5)] unused: [3]
[(2, 3), (4, 5)] unused: [1]
[(3, 4), (1, 2)] unused: [5]
[(4, 5), (1, 2)] unused: [3]
[(4, 5), (2, 3)] unused: [1]

然而我使用itertools.combinations

[(1, 2), (3, 4)] unused: [5]
[(1, 2), (4, 5)] unused: [3]
[(2, 3), (4, 5)] unused: [1]

编辑:好的,这个新修订版有点困难。我现在所做的是找到较大列表中所有子组彼此相邻的子组。我找到每个子组的组合,然后将它们全部放回到最后一个itertools.product。另外,在我的测试用例中,我在最后添加了一对(8,9)以确保一切适用于多个组。这是代码:

l = [(1,2),(2,3),(3,4),(4,5),(7,8),(8,9)]
import itertools,math

## Create sublists for each set of adjacent pairs
l.sort(lambda x,y:cmp(x[0],y[0]))
newl = []
subl = []
for i in range(len(l)):
    if subl == []:
        subl.append(l[i])
    else:
        if l[i][0] == subl[-1][1]:
            subl.append(l[i])
        else:
            newl.append(subl)
            subl = [l[i]]
newl.append(subl)
pair_lists = []

## Find all combinations for each sublist
for subl in newl:
    cur_pair_list = []
    for perm in itertools.combinations(subl,int(math.ceil(len(subl) / 2.0))):
        pair_list = []
        for pair in perm:
            if pair[0] in itertools.chain(*pair_list) \
            or pair[1] in itertools.chain(*pair_list):
                break
            pair_list.append(pair)
        if len(pair_list) == int(math.ceil(len(subl) / 2.0)):
            cur_pair_list.append(pair_list)
    pair_lists.append(cur_pair_list)

## Combine combinations for each sublist and determine unused for each combination
final_list = list(list(itertools.chain(*i)) for i in itertools.product(*pair_lists))
for subl in final_list:
    unused = []
    for n in itertools.chain(*l):
        if n not in itertools.chain(*subl) and n not in unused:
            unused.append(n)
    print subl,'unused:',unused

这是输出:

[(1, 2), (3, 4), (7, 8)] unused: [5, 9]
[(1, 2), (3, 4), (8, 9)] unused: [5, 7]
[(1, 2), (4, 5), (7, 8)] unused: [3, 9]
[(1, 2), (4, 5), (8, 9)] unused: [3, 7]
[(2, 3), (4, 5), (7, 8)] unused: [1, 9]
[(2, 3), (4, 5), (8, 9)] unused: [1, 7]

编辑#2: 所以在这里,我只需要做的新事就是改变列表的排序方式。评论## Find all combinations for each sublist下面的所有代码都可以保持不变。

以下是该评论的新代码:

l = [(427, 3434), (614, 2445), (840, 614), (910, 3939), (1065, 4314), (1347, 2616), (2445, 427), (2616, 3901), (2749, 1065), (3403, 910), (3434, 1347), (3659, 1411), (3901, 3684), (3939, 2638), (4203, 3403), (4314, 840)]
import itertools,math


def sort(l):
    l = list(l)
    newl = []
    subl = []
    i = l[0]
    while len(l) > 0:
        subl.append(i)
        l.remove(i)
        k = None
        for j in l:
            if j[0] == i[1]:
                    k = j
                    break
        if k:
            i = k
        else:
            newl.append(subl)
            subl = []
            if len(l) > 0:
                i = l[0]
    i = 0
    while i < len(newl):
        j = 0
        while j < len(newl):
            if newl[j][-1][1] == newl[i][0][0]:
                for k in newl[j][::-1]:
                    newl[i].insert(0,k)
                newl.pop(j)
                continue
            j += 1
        i += 1

    return newl

pair_lists = []
newl = sort(l)

这是我在新列表中运行时得到的输出:

[(2749, 1065), (4314, 840), (614, 2445), (427, 3434), (1347, 2616), (3901, 3684), (4203, 3403), (910, 3939), (3659, 1411)] unused: [2638]
[(2749, 1065), (4314, 840), (614, 2445), (427, 3434), (1347, 2616), (3901, 3684), (4203, 3403), (3939, 2638), (3659, 1411)] unused: [910]
[(2749, 1065), (4314, 840), (614, 2445), (427, 3434), (1347, 2616), (3901, 3684), (3403, 910), (3939, 2638), (3659, 1411)] unused: [4203]