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]

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:]

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]

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.


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]

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]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.