Có cách nào dễ hiểu để giải nén một danh sách trong phần tử đầu tiên và "đuôi" trong một lệnh duy nhất không?
Ví dụ:
>> 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]
Có cách nào dễ hiểu để giải nén một danh sách trong phần tử đầu tiên và "đuôi" trong một lệnh duy nhất không?
Ví dụ:
>> 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]
Câu trả lời:
Trong Python 3.x, bạn có thể thực hiện điều này một cách độc đáo:
>>> head, *tail = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]
Một tính năng mới trong 3.x là sử dụng *
toán tử để giải nén, có nghĩa là bất kỳ giá trị bổ sung nào. Nó được mô tả trong PEP 3132 - Mở rộng có thể lặp lại mở rộng . Điều này cũng có lợi thế là làm việc trên bất kỳ chuỗi nào có thể lặp lại, không chỉ chuỗi.
Nó cũng thực sự dễ đọc.
Như được mô tả trong PEP, nếu bạn muốn làm điều tương đương dưới 2.x (mà không có khả năng tạo danh sách tạm thời), bạn phải thực hiện điều này:
it = iter(iterable)
head, tail = next(it), list(it)
Như đã lưu ý trong các nhận xét, điều này cũng tạo cơ hội để nhận giá trị mặc định head
thay vì ném một ngoại lệ. Nếu bạn muốn hành vi này, hãy next()
lấy đối số thứ hai tùy chọn với giá trị mặc định, vì vậy next(it, None)
sẽ cung cấp cho bạn None
nếu không có phần tử head.
Đương nhiên, nếu bạn đang làm việc trên một danh sách, cách dễ nhất mà không có cú pháp 3.x là:
head, tail = seq[0], seq[1:]
__getitem__
/ thực hiện __setitem__
thao tác đuôi một cách lười biếng, nhưng danh sách tích hợp thì không.
python 3.x
Tuy nhiên, đối với độ phức tạp của head,tail
hoạt động O (1), bạn nên sử dụng deque
.
Theo đường này:
from collections import deque
l = deque([1,2,3,4,5,6,7,8,9])
head, tail = l.popleft(), l
Nó hữu ích khi bạn phải lặp qua tất cả các phần tử của danh sách. Ví dụ trong hợp nhất ngây thơ 2 phân vùng trong sắp xếp hợp nhất.
head, tail = l.popleft(), l
~ O (1). head, tail = seq[0], seq[1:]
là O (n).
head = l.popleft()
và tail
chỉ là một bí danh cho l
. Nếu l
thay tail
đổi cũng thay đổi.
Python 2, sử dụng 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]
head, tail = lst[0], lst[1:]
? nếu phương tiện OP sử dụng một chữ sau đó ông có thể chia đầu và đuôi bằng tayhead, tail = 1, [1, 2, 3, 5, 8, 13, 21, 34, 55]
lst = ...
ở dòng trước). (2) Việc làm head, tail = lst[0], lst[1:]
khiến mã mở ra các tác dụng phụ (xem xét head, tail = get_list()[0], get_list()[1:]
), và khác với hình thức của Op head, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
.
Xây dựng dựa trên giải pháp Python 2 từ @GarethLatty , sau đây là một cách để lấy một dòng tương đương mà không có biến trung gian trong Python 2.
t=iter([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);h,t = [(h,list(t)) for h in t][0]
Nếu bạn cần nó để chống ngoại lệ (tức là hỗ trợ danh sách trống), thì hãy thêm:
t=iter([]);h,t = ([(h,list(t)) for h in t]+[(None,[])])[0]
Nếu bạn muốn làm điều đó mà không có dấu chấm phẩy, hãy sử dụng:
h,t = ([(h,list(t)) for t in [iter([1,2,3,4])] for h in t]+[(None,[])])[0]