我有一个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])
有没有内置函数可以做到这一点?
我有一个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])
有没有内置函数可以做到这一点?
当前回答
前面的答案都没有有效地提供所需的输出,即一个由列表组成的元组,而不是由元组组成的列表。对于前者,您可以使用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等函数以耗尽迭代器。对于内存效率高的迭代器,可以忽略各自解的外部列表和元组调用。
其他回答
我喜欢在我的程序中使用zip(*iterable)(这是你正在寻找的代码段),如下所示:
def unzip(iterable):
return zip(*iterable)
我发现unzip更具可读性。
虽然zip(*seq)非常有用,但它可能不适合非常长的序列,因为它将创建一个值的元组来传递。例如,我一直在使用一个拥有超过100万个条目的坐标系,并发现直接创建序列要快得多。
一般的方法是这样的:
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集合可能是有意义的。
因为它返回元组(可能会使用大量内存),所以对我来说,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
如果您的列表长度不相同,您可能不希望按照patrick的回答使用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')]
你可以使用map没有函数来填充空结果为None:
>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]
不过Zip()稍微快一点。
这只是另一种方法,但它对我帮助很大,所以我写在这里:
具有这种数据结构的:
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')]
在我看来,更python化的解压方法是这样的:
x,y=zip(*XY)
但是这个返回一个元组,所以如果你需要一个列表,你可以使用:
x,y=(list(x),list(y))