Есть ли питонический способ распаковать список в первый элемент и «хвост» в одной команде?
Например:
>> 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]
Есть ли питонический способ распаковать список в первый элемент и «хвост» в одной команде?
Например:
>> 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]
Ответы:
В 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 - Extended Iterable Unpacking . Это также дает преимущество работы с любыми итерациями, а не только с последовательностями.
Это также действительно читается.
Как описано в PEP, если вы хотите сделать эквивалент в версии 2.x (без создания временного списка), вы должны сделать это:
it = iter(iterable)
head, tail = next(it), list(it)
Как отмечено в комментариях, это также дает возможность получить значение по умолчанию, head
а не генерировать исключение. Если вы хотите такое поведение, next()
принимает необязательный второй аргумент со значением по умолчанию, поэтому next(it, None)
он даст вам, None
если бы не было элемента head.
Естественно, если вы работаете со списком, самый простой способ без синтаксиса 3.x:
head, tail = seq[0], seq[1:]
__getitem__
/ __setitem__
выполнять хвостовую операцию, но встроенный список этого не делает.
python 3.x
Однако для сложности head,tail
операции O (1) вы должны использовать deque
.
Следующим способом:
from collections import deque
l = deque([1,2,3,4,5,6,7,8,9])
head, tail = l.popleft(), l
Это полезно, когда вы должны перебирать все элементы списка. Например, при наивном слиянии двух разделов в сортировке слияния.
head, tail = l.popleft(), l
это ~ O (1). head, tail = seq[0], seq[1:]
равно O (n).
head = l.popleft()
и tail
это просто псевдоним для l
. Если l
изменения tail
изменения тоже.
Python 2 с использованием лямбда
>>> 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]
head, tail = lst[0], lst[1:]
? если OP подразумевает использование буквального слова, то он может вручную разделить голову и хвостhead, tail = 1, [1, 2, 3, 5, 8, 13, 21, 34, 55]
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]
.
Основываясь на решении Python 2 от @GarethLatty , ниже представлен способ получить однострочный эквивалент без промежуточных переменных в 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]