Baş ve kuyruk tek satırda


93

Birinci öğedeki bir listeyi ve tek bir komuttaki "kuyruk" u açmanın pitonik bir yolu var mı?

Örneğin:

>> 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'da listelerin tek bağlantılı listeler olarak uygulanmadığını unutmayın, bu nedenle bu işlem maliyetlidir (olduğu gibi: tüm listenin kopyalanması gerekir). Neyi başarmak istediğinize bağlı olarak, bu bir sorun olabilir veya olmayabilir. Sadece bu tür bir liste yok etme işleminin genellikle çok ucuz bir işlem olduğu işlevsel dillerde bulunduğundan bahsediyorum.
Niklas B.

Yanıtlar:


193

Python 3.x altında, bunu güzelce yapabilirsiniz:

>>> 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'teki yeni bir özellik, *herhangi bir ekstra değer anlamında operatörü ambalajı açarken kullanmaktır . PEP 3132 - Uzatılmış Tekrarlanabilir Ambalajdan Çıkarma'da açıklanmaktadır . Bu aynı zamanda sadece sekanslar üzerinde değil, herhangi bir tekrarlanabilir üzerinde çalışma avantajına da sahiptir.

Aynı zamanda gerçekten okunabilir.

PEP'de açıklandığı gibi, eşdeğerini 2.x altında yapmak istiyorsanız (potansiyel olarak geçici bir liste oluşturmadan), bunu yapmanız gerekir:

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

Yorumlarda belirtildiği gibi, bu aynı zamanda headbir istisna atmak yerine varsayılan bir değer elde etme fırsatı da sağlar . Bu davranışı istiyorsanız, next()varsayılan bir değere sahip isteğe bağlı ikinci bir argüman alır, böylece head öğesi yoksa next(it, None)size verir None.

Doğal olarak, bir liste üzerinde çalışıyorsanız, 3.x sözdizimi olmadan en kolay yol şudur:

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

1
üzgünüm, kuyruk terimini yanlış kullandım. Örnekte söylediğimi kastediyorum, bu ilk unsurun olmadığı liste
Giacomo d'Antonio

1
@NikolayFominyh İkisi de aynı - ikisi de head elementini alıyor ve tail elementleri içeren yeni bir liste oluşturuyor. Karmaşıklıkta fark yok. Başka bir sınıf kuyruk işlemini tembel olarak uygulayabilir __getitem__/ __setitem__yapabilir, ancak yerleşik liste bunu yapmaz.
Gareth Latty

2
Bunu 1M kez yapan 800 öğeden oluşan bir listede, head için 2.8s, * tail = seq çözümü ve head, tail = seq [0], seq [1:] çözümü için yalnızca 1.8s var. Dilimleme, listeler için hala daha hızlıdır.
Cabu

2
@CMCDragonkai Hayır, Python'un ana liste sınıfı bir dizi listesidir. Bu, kuyruğun yeni bir listeye kopyalanmasını içerdiğinden O (n) olacaktır (bir O (1) kafa için alın).
Gareth Latty

1
Bu güzel sözdizimi, taşınmak için başka bir nedenpython 3.x
eigenfield

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,tailoperasyon karmaşıklığı için, dequeancak kullanmanız gerekir .

Takip eden yol:

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

Listenin tüm öğelerini yinelemeniz gerektiğinde kullanışlıdır. Örneğin, birleştirme sıralamasında 2 bölümün saf birleştirilmesinde.


Görünüşe göre deque (list_instance) O (N) karmaşıklığına sahip. Yanlış mıyım?
Никита Конин

1
@ НикитаКонин, dekor yapımı konusunda haklısınız. Bununla birlikte, ilk elemana birden çok kez erişmek istiyorsanız, o head, tail = l.popleft(), lzaman ~ O (1) olur. head, tail = seq[0], seq[1:]O (n).
Nikolay Fominyh

Yapabileceğin gibi görünüyor head = l.popleft()ve tailbunun sadece bir takma adı l. Eğer ldeğişiklikler tailde değişir.
kon psych

2

Python 2, lambda kullanarak

>>> 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
neden bunu sadece yapmak yerine yaparsın head, tail = lst[0], lst[1:]? OP kelimesi kelimesi kelimesini kullanmak anlamına gelirse, o zaman baş ve kuyruğu manuel olarak bölebilirhead, tail = 1, [1, 2, 3, 5, 8, 13, 21, 34, 55]
Filipe Pina

1
(1) Op'un sorusu, bunu bir satırda yapmanın mümkün olup olmadığı idi (yani lst = ...önceki satırda hayır ). (2) Yapmak head, tail = lst[0], lst[1:], kodu yan etkilere açık bırakır (düşünün head, tail = get_list()[0], get_list()[1:]) ve Op'ın formundan farklıdır head, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55].
BobIsNotMyName

Bununla birlikte, bunun başı / kuyruğu almak için kötü bir şaşkınlık yolu olduğunu kabul ediyorum. Ancak Op'un özel sorusu için Python 2 için en iyi cevap olduğunu düşündüm.
BobIsNotMyName

1

Bina @GarethLatty Python 2 çözeltisi , aşağıdaki Python 2 içinde bir ara madde değişken olmayan tek bir satırı eşdeğeri almak için bir yöntemdir.

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

İstisnalara karşı korumalı olması gerekiyorsa (yani boş listeyi destekliyor), o zaman şunu ekleyin:

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

Bunu noktalı virgül olmadan yapmak istiyorsanız, şunu kullanın:

h,t = ([(h,list(t)) for t in [iter([1,2,3,4])] for h in t]+[(None,[])])[0]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.