Kepala dan ekor dalam satu baris

92

Apakah ada cara pythonic untuk membongkar daftar di elemen pertama dan "tail" dalam satu perintah?

Sebagai contoh:

>> 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]
Giacomo d'Antonio
sumber
9
Ingatlah bahwa daftar tidak diimplementasikan sebagai daftar tertaut tunggal di Python, jadi operasi ini mahal (seperti dalam: seluruh daftar perlu disalin). Bergantung pada apa yang ingin Anda capai, ini mungkin atau mungkin tidak menjadi masalah. Saya hanya menyebutkan itu karena jenis penghancuran daftar ini sering ditemukan dalam bahasa fungsional, yang sebenarnya merupakan operasi yang sangat murah.
Niklas B.

Jawaban:

192

Di bawah Python 3.x, Anda dapat melakukan ini dengan baik:

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

Fitur baru di 3.x adalah menggunakan *operator dalam membongkar, yang berarti nilai tambahan apa pun. Ini dijelaskan dalam PEP 3132 - Extended Iterable Unpacking . Ini juga memiliki keuntungan untuk mengerjakan iterable apa pun, bukan hanya urutan.

Ini juga sangat mudah dibaca.

Seperti dijelaskan dalam PEP, jika Anda ingin melakukan hal yang setara di bawah 2.x (tanpa berpotensi membuat daftar sementara), Anda harus melakukan ini:

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

Seperti disebutkan dalam komentar, ini juga memberikan kesempatan untuk mendapatkan nilai default headdaripada membuat pengecualian. Jika Anda menginginkan perilaku ini, gunakan next()argumen opsional kedua dengan nilai default, yang next(it, None)akan memberi Anda Nonejika tidak ada elemen head.

Biasanya, jika Anda mengerjakan daftar, cara termudah tanpa sintaks 3.x adalah:

head, tail = seq[0], seq[1:]
Gareth Latty
sumber
1
maaf, saya menggunakan istilah ekor secara tidak benar. Maksud saya apa yang saya katakan dalam contoh, itu adalah daftar tanpa elemen pertama
Giacomo d'Antonio
1
@NikolayFominyh Keduanya sama - keduanya mengambil elemen head dan membuat daftar baru yang berisi elemen ekor. Tidak ada perbedaan dalam kompleksitas. Kelas lain bisa mengimplementasikan __getitem__/ __setitem__melakukan operasi tail dengan malas, tetapi daftar bawaan tidak.
Gareth Latty
2
Pada daftar 800 elemen yang melakukannya 1 juta kali, saya memiliki 2,8s untuk head, solusi * tail = seq dan hanya 1,8s untuk solusi head, tail = seq [0], seq [1:]. Mengiris masih lebih cepat untuk daftar.
Cabu
2
@CMCDragonkai Tidak, kelas daftar utama Python adalah daftar larik. Ini akan menjadi O (n) karena ini melibatkan penyalinan ekor ke daftar baru (dengan satu O (1) get untuk kepala).
Gareth Latty
1
Sintaks yang bagus ini adalah alasan lain untuk pindah kepython 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]
fraxel
sumber
9

Untuk kompleksitas head,tailoperasi O (1), Anda harus menggunakan deque.

Cara berikut:

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

Ini berguna ketika Anda harus mengulangi semua elemen daftar. Misalnya dalam menggabungkan 2 partisi secara naif dalam merge sort.

Nikolay Fominyh
sumber
Sepertinya deque (list_instance) memiliki kompleksitas O (N). Apakah aku salah?
Никита Конин
1
@ НикитаКонин, Anda benar tentang konstruksi deque. Namun, jika Anda ingin mengakses elemen pertama lebih dari satu kali, maka head, tail = l.popleft(), l~ O (1). head, tail = seq[0], seq[1:]adalah O (n).
Nikolay Fominyh
Sepertinya Anda bisa melakukannya head = l.popleft()dan tailhanya alias untuk l. Jika lperubahan tailperubahan juga.
hubungi
2

Python 2, menggunakan 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]
BobIsNotMyName
sumber
1
mengapa di dunia ini Anda melakukan ini, bukan hanya head, tail = lst[0], lst[1:]? jika OP berarti menggunakan literal maka dia bisa membelah kepala dan ekor secara manualhead, tail = 1, [1, 2, 3, 5, 8, 13, 21, 34, 55]
Filipe Pina
1
(1) Pertanyaan Op adalah apakah mungkin melakukan ini dalam satu baris (jadi tidak lst = ...di baris sebelumnya). (2) Melakukan head, tail = lst[0], lst[1:]membuat kode terbuka untuk efek samping (pertimbangkan head, tail = get_list()[0], get_list()[1:]), dan berbeda dari bentuk Op head, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55].
BobIsNotMyName
Karena itu, saya mengakui bahwa ini adalah cara yang tidak jelas untuk mendapatkan kepala / ekor. Tapi saya pikir itu adalah jawaban terbaik untuk Python 2 untuk pertanyaan spesifik Op.
BobIsNotMyName
1

Membangun solusi Python 2 dari @GarethLatty , berikut ini adalah cara untuk mendapatkan satu baris yang setara tanpa variabel perantara di Python 2.

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

Jika Anda membutuhkannya untuk menjadi pengecualian-bukti (yaitu mendukung daftar kosong), maka tambahkan:

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

Jika Anda ingin melakukannya tanpa titik koma, gunakan:

h,t = ([(h,list(t)) for t in [iter([1,2,3,4])] for h in t]+[(None,[])])[0]
ABridgeTooFar
sumber