我有一个2项元组的列表,我想将它们转换为2个列表,其中第一个包含每个元组中的第一个项目,第二个列表包含第二个项目 .
For example:
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(*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
zip是它自己的逆!如果您使用特殊*运算符 .
>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]) [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
这种方式的工作方式是使用参数调用 zip :
zip
zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))
...除了参数直接传递给 zip (转换为元组后),所以不必担心参数数量过大 .
以前的答案都没有有效地提供所需的输出,这是一个 tuple of lists ,而不是元组列表 . 对于前者,您可以将 tuple 与 map 一起使用 . 这是区别:
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 )以耗尽迭代器 . 对于内存有效的迭代器,您可以省略相应解决方案的外部 list 和 tuple 调用 .
list
这就是你可以将2x4元组转换成4x2元组的方法 .
>>> tuple(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))
结果
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
你也可以这样做
result = ([ a for a,b in original ], [ b for a,b in original ])
它应该更好地扩展 . 特别是如果Python擅长不扩展列表推导,除非需要 .
(顺便说一句,它产生了一个2元组(对)列表,而不是像元组列表那样的元组,如 zip .
如果生成器而不是实际列表是可以的,那么这样做:
result = (( a for a,b in original ), ( b for a,b in original ))
在您询问每个元素之前,生成器不会遍历列表,但另一方面,它们会保留对原始列表的引用 .
考虑 unzip 或 transpose 的另一种方法是将行列表转换为列列表 .
unzip
transpose
pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clements'), ('Schilling','Curt')] first_names, last_names = zip(*pitchers) In [45]: first_names Out[45]: ('Nolan', 'Roger', 'Schilling') In [46]: last_names Out[46]: ('Ryan', 'Clements', 'Curt')
这只是另一种方式,但它帮了我很多,所以我在这里写:
拥有这样的数据结构:
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)
但这会返回一个元组,所以如果你需要一个列表,你可以使用:
x,y=(list(x),list(y))
>>> 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)]
解压缩两个列表 .
如果您的列表长度不同,则可能不希望按照Patricks的说法使用zip . 这有效:
但是使用不同的长度列表,zip会将每个项目截断为最短列表的长度:
>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )]) [('a', 'b', 'c', 'd', 'e')]
您可以使用没有函数的map来使用None填充空结果:
>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )]) [('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]
zip()虽然略快 .
我喜欢在我的程序中使用 zip(*iterable) (这是你要查找的代码段),如下所示:
zip(*iterable)
def unzip(iterable): return zip(*iterable)
我发现 unzip 更具可读性 .
虽然 zip(*seq) 非常有用,但它可能不适用于很长的序列,因为它会创建一个值传入的元组 . 例如,我一直在使用一个超过一百万个条目的坐标系,并且发现它显着更快到直接创建序列 .
zip(*seq)
通用的方法是这样的:
from collections import deque seq = ((a1, b1, …), (a2, b2, …), …) width = len(seq[0]) output = [deque(len(seq))] * width # preallocate memory for element in seq: for s, item in zip(output, element): s.append(item)
但是,根据您想要对结果做什么,选择集合可以产生很大的不同 . 在我的实际使用案例中,使用集合而没有内部循环,明显快于所有其他方法 .
并且,正如其他人所指出的,如果您使用数据集执行此操作,则可能需要使用Numpy或Pandas集合 .
11 回答
既然它返回了元组(并且可以使用大量的内存),那么
zip(*zipped)
技巧对我来说似乎更有用 .这是一个实际上会给你反转zip的函数 .
zip是它自己的逆!如果您使用特殊*运算符 .
这种方式的工作方式是使用参数调用
zip
:...除了参数直接传递给
zip
(转换为元组后),所以不必担心参数数量过大 .以前的答案都没有有效地提供所需的输出,这是一个 tuple of lists ,而不是元组列表 . 对于前者,您可以将
tuple
与map
一起使用 . 这是区别:此外,以前的大多数解决方案都假设使用Python 2.7,其中
zip
返回列表而不是迭代器 .对于Python 3.x,您需要将结果传递给函数(如
list
或tuple
)以耗尽迭代器 . 对于内存有效的迭代器,您可以省略相应解决方案的外部list
和tuple
调用 .这就是你可以将2x4元组转换成4x2元组的方法 .
结果
你也可以这样做
它应该更好地扩展 . 特别是如果Python擅长不扩展列表推导,除非需要 .
(顺便说一句,它产生了一个2元组(对)列表,而不是像元组列表那样的元组,如
zip
.如果生成器而不是实际列表是可以的,那么这样做:
在您询问每个元素之前,生成器不会遍历列表,但另一方面,它们会保留对原始列表的引用 .
考虑
unzip
或transpose
的另一种方法是将行列表转换为列列表 .这只是另一种方式,但它帮了我很多,所以我在这里写:
拥有这样的数据结构:
导致:
在我看来,解压缩并回归原始的更加pythonic的方式是:
但这会返回一个元组,所以如果你需要一个列表,你可以使用:
在问题中给出一个列表元组 .
解压缩两个列表 .
如果您的列表长度不同,则可能不希望按照Patricks的说法使用zip . 这有效:
但是使用不同的长度列表,zip会将每个项目截断为最短列表的长度:
您可以使用没有函数的map来使用None填充空结果:
zip()虽然略快 .
我喜欢在我的程序中使用
zip(*iterable)
(这是你要查找的代码段),如下所示:我发现
unzip
更具可读性 .虽然
zip(*seq)
非常有用,但它可能不适用于很长的序列,因为它会创建一个值传入的元组 . 例如,我一直在使用一个超过一百万个条目的坐标系,并且发现它显着更快到直接创建序列 .通用的方法是这样的:
但是,根据您想要对结果做什么,选择集合可以产生很大的不同 . 在我的实际使用案例中,使用集合而没有内部循环,明显快于所有其他方法 .
并且,正如其他人所指出的,如果您使用数据集执行此操作,则可能需要使用Numpy或Pandas集合 .