转置/解压缩函数(zip的逆操作)?
我有一个包含二元组的列表,想把它们转换成两个列表,第一个列表里放每个元组的第一个元素,第二个列表里放每个元组的第二个元素。
比如说:
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)]