我有一个2项元组的列表,我想将它们转换为2个列表,其中第一个包含每个元组中的第一项,第二个列表包含第二项。

例如:

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

有没有内置函数可以做到这一点?


当前回答

因为它返回元组(可能会使用大量内存),所以对我来说,zip(*zipped)技巧似乎更聪明而不是有用。

这是一个函数,它会给出zip的倒数。

def unzip(zipped):
    """Inverse of built-in zip function.
    Args:
        zipped: a list of tuples

    Returns:
        a tuple of lists

    Example:
        a = [1, 2, 3]
        b = [4, 5, 6]
        zipped = list(zip(a, b))

        assert zipped == [(1, 4), (2, 5), (3, 6)]

        unzipped = unzip(zipped)

        assert unzipped == ([1, 2, 3], [4, 5, 6])

    """

    unzipped = ()
    if len(zipped) == 0:
        return unzipped

    dim = len(zipped[0])

    for i in range(dim):
        unzipped = unzipped + ([tup[i] for tup in zipped], )

    return unzipped

其他回答

前面的答案都没有有效地提供所需的输出,即一个由列表组成的元组,而不是由元组组成的列表。对于前者,您可以使用tuple与map。区别在于:

res1 = list(zip(*original))              # [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
res2 = tuple(map(list, zip(*original)))  # (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

此外,前面的大多数解决方案都假设Python 2.7,其中zip返回一个列表而不是迭代器。

对于Python 3。X时,您需要将结果传递给list或tuple等函数以耗尽迭代器。对于内存效率高的迭代器,可以忽略各自解的外部列表和元组调用。

在2。X, zip是它自己的逆!前提是使用特殊的*操作符。

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

这相当于将列表中的每个元素作为单独的参数调用zip:

zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))

除非参数被直接传递给zip(在被转换为元组之后),所以没有必要担心参数的数量变得太大。

在3。X, zip返回一个惰性迭代器,但这是简单的转换:

>>> list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

因为它返回元组(可能会使用大量内存),所以对我来说,zip(*zipped)技巧似乎更聪明而不是有用。

这是一个函数,它会给出zip的倒数。

def unzip(zipped):
    """Inverse of built-in zip function.
    Args:
        zipped: a list of tuples

    Returns:
        a tuple of lists

    Example:
        a = [1, 2, 3]
        b = [4, 5, 6]
        zipped = list(zip(a, b))

        assert zipped == [(1, 4), (2, 5), (3, 6)]

        unzipped = unzip(zipped)

        assert unzipped == ([1, 2, 3], [4, 5, 6])

    """

    unzipped = ()
    if len(zipped) == 0:
        return unzipped

    dim = len(zipped[0])

    for i in range(dim):
        unzipped = unzipped + ([tup[i] for tup in zipped], )

    return unzipped

总结一下:

# data
a = ('a', 'b', 'c', 'd')
b = (1, 2, 3, 4)

# forward
zipped = zip(a, b)  # [('a', 1), ('b', 2), ('c', 3), ('d', 4)]

# reverse
a_, b_ = zip(*zipped)

# verify
assert a == a_
assert b == b_

要获得一个列表的元组,如问题中所示:

>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple([list(tup) for tup in zip(*original)])
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

要将两个列表解压缩为单独的变量:

list1, list2 = [list(tup) for tup in zip(*original)]