转置/解压缩函数(zip的逆操作)?

606 投票
14 回答
208550 浏览
提问于 2025-04-10 23:34

我有一个包含二元组的列表,想把它们转换成两个列表,第一个列表里放每个元组的第一个元素,第二个列表里放每个元组的第二个元素。

比如说:

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

有没有现成的函数可以做到这一点呢?

14 个回答

24

我喜欢在我的程序中使用 zip(*iterable) 这个代码(就是你想要找的那段代码),用法如下:

def unzip(iterable):
    return zip(*iterable)

我觉得 unzip 更容易理解。

29

你也可以这样做:

result = ([ a for a,b in original ], [ b for a,b in original ])

这样做应该能更好地扩展,特别是如果Python在需要的时候才扩展列表推导式的话。

顺便提一下,这样做会生成一个包含两个列表的元组,而不是像zip那样生成一个元组列表。

如果可以使用生成器而不是实际的列表,这样做就可以:

result = (( a for a,b in original ), ( b for a,b in original ))

生成器不会在你请求每个元素之前就消耗掉整个列表,但另一方面,它们会保留对原始列表的引用。

910

在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)]

撰写回答