转置/解压缩函数(zip的反转)?

我有一个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]) 

是否有一个内置的function呢?

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 (在转换为元组之后)之外,因此不必担心参数数量太大。

你也可以做

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

应该更好地扩展。 特别是如果Python不擅长扩展列表parsing,除非需要。

(顺便说一下,它使一个2元组(一对)的列表,而不是一个元组列表,如zip

如果生成器而不是实际列表是可以的,这将做到这一点:

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

生成器不会在列表中find每个元素,但是另一方面,它们保持对原始列表的引用。

如果您的列表长度不相同,则可能不希望按照Patricks的答案使用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), ('e', )]) [('a', 'b', 'c', 'd', 'e')] 

您可以使用无function的地图来填充空白结果:

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

zip()稍微快一点。

我喜欢在我的程序中使用zip(*iterable) (这是您要查找的代码片段),如下所示:

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

我觉得unzip更可读。

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

解压两个列表。

这只是另一种方式去做,但它帮助了我很多,所以我写在这里:

有这样的数据结构:

 X=[1,2,3,4] Y=['a','b','c','d'] XY=zip(X,Y) 

导致:

 In: XY Out: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')] 

在我看来,解压缩并回到原来的更加pythonic的方式是这样的:

 x,y=zip(*XY) 

但是这返回一个元组,所以如果你需要一个数组,你可以使用:

 xy=(list(x),list(y))