头尾一条线


90

有没有一种Python方式可以在单个命令中解压缩第一个元素和“ tail”中的列表?

例如:

>> head, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

9
请记住,列表未在Python中实现为单链接列表,因此此操作的成本很高(例如:需要复制整个列表)。根据您要实现的目标,这可能是问题,也可能不是问题。我只是提到,因为这类列表解构通常是在函数式语言中发现的,实际上这是一种非常便宜的操作。
Niklas B.

Answers:


188

在Python 3.x下,您可以很好地做到这一点:

>>> head, *tail = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

3.x的一项新功能是*在解包时使用运算符,以表示任何其他值。在PEP 3132-扩展的可迭代拆包中对此进行了描述。这也具有处理任何可迭代的,而不仅仅是序列的优点。

它也确实可读。

如PEP中所述,如果要在2.x下执行等效操作(而不可能创建临时列表),则必须执行以下操作:

it = iter(iterable)
head, tail = next(it), list(it)

如评论中所述,这也提供了获得默认值head而不是引发异常的机会。如果您要执行此操作,请next()使用可选的第二个参数作为默认值,如果没有head元素,next(it, None)则会给出提示None

自然,如果您正在处理列表,则不使用3.x语法的最简单方法是:

head, tail = seq[0], seq[1:]

1
抱歉,我不恰当地使用了“ tail”一词。我的意思是我在示例中说的是没有第一个元素的列表
Giacomo d'Antonio'5

1
@NikolayFominyh它们都是相同的-它们都采用head元素并构造一个包含tail元素的新列表。复杂度没有差异。另一个类可以实现__getitem__/ __setitem__延迟执行尾操作,但是内置列表则不能。
Gareth Latty

2
在执行1M次的800个元素列表中,我的头部为2.8s,* tail = seq解决方案,而头部为1.8s,尾部= seq [0],seq [1:]解决方案。列表的切片速度仍然更快。
Cabu

2
@CMCDragonkai不,Python的主列表类是数组列表。这将是O(n),因为它涉及将尾部复制到新列表(头部为O(1))。
Gareth Latty

1
这种不错的语法是移至python 3.x
eigenfield '18

36
>>> mylist = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> head, tail = mylist[0], mylist[1:]
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

9

对于O(1)head,tail操作复杂性,您应该使用deque

遵循的方式:

from collections import deque
l = deque([1,2,3,4,5,6,7,8,9])
head, tail = l.popleft(), l

当您必须遍历列表的所有元素时,这很有用。例如,在朴素的情况下,在合并排序中合并2个分区。


似乎deque(list_instance)具有O(N)复杂度。我错了吗?
НикитаКонин

1
@НикитаКонин,您对双端队列的构造是正确的。但是,如果要多次访问第一个元素,head, tail = l.popleft(), l则为〜O(1)。head, tail = seq[0], seq[1:]是O(n)。
Nikolay Fominyh

看起来您可以做到head = l.popleft()tail并且只是的别名l。如果l变化也tail变化。
kon心理

2

Python 2,使用Lambda

>>> head, tail = (lambda lst: (lst[0], lst[1:]))([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

1
为什么在世界上您会这样做而不仅仅是head, tail = lst[0], lst[1:]?如果OP表示要使用文字,那么他可以手动拆分头和尾head, tail = 1, [1, 2, 3, 5, 8, 13, 21, 34, 55]
Filipe Pina

1
(1)Op的问题是是否可以在一行中执行此操作(因此lst = ...在上一行中没有)。(2)这样做head, tail = lst[0], lst[1:]会使代码易于产生副作用(请考虑head, tail = get_list()[0], get_list()[1:]),并且与Op的形式不同head, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
BobIsNotMyName

话虽如此,我承认这是弄乱头/尾巴的一种不好的混淆方法。但是我认为这是针对Op 2的特定问题的Python 2的最佳答案。
BobIsNotMyName

1

@GarethLattyPython 2解决方案的基础上,以下是一种在Python 2中获得没有等效中间变量的单行等效方法。

t=iter([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);h,t = [(h,list(t)) for h in t][0]

如果您需要它是防异常的(即支持空列表),请添加:

t=iter([]);h,t = ([(h,list(t)) for h in t]+[(None,[])])[0]

如果要在不使用分号的情况下执行此操作,请使用:

h,t = ([(h,list(t)) for t in [iter([1,2,3,4])] for h in t]+[(None,[])])[0]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.