我有一个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])
有没有内置函数可以做到这一点?
当前回答
这只是另一种方法,但它对我帮助很大,所以我写在这里:
具有这种数据结构的:
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(*iterable)(这是你正在寻找的代码段),如下所示:
def unzip(iterable):
return zip(*iterable)
我发现unzip更具可读性。
你也可以
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 ))
在您请求每个元素之前,生成器不会仔细检查列表,但另一方面,它们会保留对原始列表的引用。
前面的答案都没有有效地提供所需的输出,即一个由列表组成的元组,而不是由元组组成的列表。对于前者,您可以使用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等函数以耗尽迭代器。对于内存效率高的迭代器,可以忽略各自解的外部列表和元组调用。
虽然numpy数组和pandas可能更可取,但此函数在作为unzip(args)调用时模仿zip(*args)的行为。
允许生成器(如Python 3中zip的结果)在遍历值时作为参数传递。
def unzip(items, cls=list, ocls=tuple):
"""Zip function in reverse.
:param items: Zipped-like iterable.
:type items: iterable
:param cls: Container factory. Callable that returns iterable containers,
with a callable append attribute, to store the unzipped items. Defaults
to ``list``.
:type cls: callable, optional
:param ocls: Outer container factory. Callable that returns iterable
containers. with a callable append attribute, to store the inner
containers (see ``cls``). Defaults to ``tuple``.
:type ocls: callable, optional
:returns: Unzipped items in instances returned from ``cls``, in an instance
returned from ``ocls``.
"""
# iter() will return the same iterator passed to it whenever possible.
items = iter(items)
try:
i = next(items)
except StopIteration:
return ocls()
unzipped = ocls(cls([v]) for v in i)
for i in items:
for c, v in zip(unzipped, i):
c.append(v)
return unzipped
要使用列表容器,只需运行unzip(zip),如
unzip(zip(["a","b","c"],[1,2,3])) == (["a","b","c"],[1,2,3])
要使用deques或其他带有附加的容器,需要传递一个工厂函数。
from collections import deque
unzip([("a",1),("b",2)], deque, list) == [deque(["a","b"]),deque([1,2])]
(装饰cls和/或main_cls以微管理容器初始化,如上面最后的assert语句所简单显示的那样。)
这只是另一种方法,但它对我帮助很大,所以我写在这里:
具有这种数据结构的:
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))