将对列表转换为与第一项共享最后一项的对的列表,反之亦然

时间:2016-05-19 18:48:51

标签: python tuples

我有一个像li = [('aa', 'bb'), ('bb','cc'), ('dd', 'ee')]这样的元组列表。从li开始,我想生成一对元组对,其中li中一个元组的第一个元素等于li的另一个元素中的第二个元素。在此处的示例中,输出列表将是包含一对元组的列表:

[(('aa', 'bb'), ('bb', 'cc'))]

这对于简短的li列表来说非常简单。我已经通过类似

之类的方式完成了它
joints = []
for pair in itertools.permutations(li, r=2):
    if pair[0][1] == pair[1][0]:
        joints += ((pair[0][0], pair[0][1]), (pair[1][0], pair[1][1]))

但是,对于长列表li,所有长度为2的排列的总数会迅速爆炸并变得无法管理。

我认为必须有一种更可行的方法来实现这一点,可能使用矩阵乘法或哈希表。更长时间(例如5000 +长度)列表的合理方法是什么?

2 个答案:

答案 0 :(得分:2)

您可以使用字典,以收集预期的对。作为更加pythonic的方法,您可以使用defaultdict()模块中的dequecollections函数,以保留deque中每对的相关对:

>>> from collections import defaultdict, deque
>>> d = defaultdict(deque)

>>> for i, j in li:
...     for k, t in li:
...        if (i, j) != (k, t) and (i == t or j == k):
...             d[(i, j)].append((k, t))
... 
>>> 
>>> d
defaultdict(<type 'collections.deque'>,
            {('dd', 'ee'): deque([('ee', 'mm')]),
             ('rr', 'cc'): deque([('cc', 'tt')]),
             ('cc', 'tt'): deque([('bb', 'cc'), ('rr', 'cc')]),
             ('aa', 'bb'): deque([('bb', 'cc')]),
             ('ee', 'mm'): deque([('dd', 'ee')]),
             ('bb', 'cc'): deque([('aa', 'bb'), ('cc', 'tt')])})

为了创建所需的元组列表,您可以使用列表推导,通过迭代字典项:

>>> [[(k, v) for v in values] for k, values in d.items()]
[[(('dd', 'ee'), ('ee', 'mm'))], [(('rr', 'cc'), ('cc', 'tt'))], [(('cc', 'tt'), ('bb', 'cc')), (('cc', 'tt'), ('rr', 'cc'))], [(('aa', 'bb'), ('bb', 'cc'))], [(('ee', 'mm'), ('dd', 'ee'))], [(('bb', 'cc'), ('aa', 'bb')), (('bb', 'cc'), ('cc', 'tt'))]]

请注意,如果您不希望对结果执行任何额外操作,则只需使用list作为defaultdict的功能,但如果您想要执行更多操作对结果的操作,如弹出,双边附加,旋转等,deque是一个不错的选择,因为为大多数操作提供了持续的顺序。

itertools.permutations更简洁的方式:

>>> from itertools import permutations
>>> for i, j permutations(li, 2):
...        if (i == t or j == k):
...             d[(i, j)].append((k, t))

答案 1 :(得分:0)

维持两组 - 第一个索引的元素和第二个索引的元素。从原始列表中,只附加那些元素中至少有一个元素在这两个元组中的元组。

li = [('aa', 'bb'), ('bb','cc'), ('dd', 'ee')]

first_pos = {x for x, y in li}
second_pos = {y for x, y in li}

arr = [(x, y) for x, y in li if (x in first_pos and x in second_pos) or (y in
    first_pos and y in second_pos)]

print(arr)

输出 -

[('aa', 'bb'), ('bb', 'cc')]