我有一个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])
有没有内置函数可以做到这一点?
当前回答
下面是一个简单的单行回答,可以产生所需的输出:
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
list(zip(*original))
# [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
其他回答
总结一下:
# data
a = ('a', 'b', 'c', 'd')
b = (1, 2, 3, 4)
# forward
zipped = zip(a, b) # [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# reverse
a_, b_ = zip(*zipped)
# verify
assert a == a_
assert b == b_
这只是另一种方法,但它对我帮助很大,所以我写在这里:
具有这种数据结构的:
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))
因为它返回元组(可能会使用大量内存),所以对我来说,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(*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集合可能是有意义的。
你也可以
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 ))
在您请求每个元素之前,生成器不会仔细检查列表,但另一方面,它们会保留对原始列表的引用。