2008-08-21 42 views
342

Tôi có danh sách các mục 2 mục và tôi muốn chuyển đổi chúng thành 2 danh sách, nơi đầu tiên chứa mục đầu tiên trong mỗi bộ và danh sách thứ hai chứa mục thứ hai.Chức năng chuyển/giải nén (nghịch đảo của mã zip)?

Ví dụ:

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)] 
# and I want to become... 
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4]) 

Có một hàm dựng sẵn nào đó?

+3

Câu trả lời tuyệt vời bên dưới, nhưng cũng xem [chuyển dịch của numpy] (http://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html) – opyate

+1

Xem câu trả lời hay để làm điều tương tự máy phát điện thay vì danh sách: [how-to-unzip-an-iterator] (http://stackoverflow.com/questions/30805000/how-to-unzip-an-iterator) – YvesgereY

Trả lời

546

zip là nghịch đảo của riêng nó! Miễn là bạn sử dụng toán tử * đặc biệt.

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]) 
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)] 

Cách làm việc này là bằng cách gọi zip với các đối số:

zip(('a', 1), ('b', 2), ('c', 3), ('d', 4)) 

... trừ các đối số được truyền cho zip trực tiếp (sau khi được chuyển đổi sang một tuple), do đó không cần phải lo lắng về số lượng các đối số nhận được quá lớn.

+6

Ồ, nếu nó đơn giản như vậy. Giải nén 'zip ([], [])' theo cách này không giúp bạn '[], []'. Nó giúp bạn '[]'. Nếu chỉ ... – user2357112

+0

@ user2357112 nó cung cấp cho bạn 'zip (* zip ([list1], [list2]))' cung cấp cho bạn '([list1, list2])'. – cdhagmann

+0

@cdhagmann: 'zip ([list1], [list2])' không bao giờ là thứ bạn muốn. Điều đó chỉ cung cấp cho bạn '[(list1, list2)]'. – user2357112

22

Bạn cũng có thể làm

result = ([ a for a,b in original ], [ b for a,b in original ]) 

nên quy mô tốt hơn. Đặc biệt nếu Python làm tốt trên việc không mở rộng việc hiểu danh sách trừ khi cần thiết.

(Ngẫu nhiên, nó làm cho một 2-tuple (cặp) của danh sách, chứ không phải là một danh sách các hàng, như zip làm.)

Nếu máy phát điện thay vì danh sách thực tế là ok, điều này sẽ làm điều đó:

result = ((a for a,b in original), (b for a,b in original)) 

Máy phát không munch qua danh sách cho đến khi bạn yêu cầu từng phần tử, nhưng mặt khác, chúng giữ tham chiếu đến danh sách gốc.

+6

"Đặc biệt nếu Python làm tốt trên việc không mở rộng danh sách hiểu, trừ khi cần thiết." mmm ... thông thường, việc hiểu danh sách được mở rộng ngay lập tức - hay tôi có điều gì sai? – glglgl

+0

@glglgl: Không, có lẽ bạn đã đúng. Tôi chỉ hy vọng một số phiên bản tương lai có thể bắt đầu làm điều đúng đắn. (Nó không phải là không thể thay đổi, ngữ nghĩa tác dụng phụ cần thay đổi có lẽ đã được khuyến khích.) –

+8

Những gì bạn hy vọng để có được một expresion máy phát điện - mà đã tồn tại. – glglgl

19

Nếu bạn có danh sách không có cùng độ dài, bạn có thể không muốn sử dụng zip theo câu trả lời của Patricks. Đây hoạt động:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]) 
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)] 

Nhưng với danh sách dài khác nhau, zip truncates từng hạng mục với độ dài của danh sách ngắn:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e',)]) 
[('a', 'b', 'c', 'd', 'e')] 

Bạn có thể sử dụng bản đồ không có chức năng để điền vào kết quả sản phẩm nào với None:

>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e',)]) 
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)] 

zip() nhanh hơn một chút.

+3

thú vị, bạn có thể giải thích cách 'map' hoạt động như thế không? –

+4

Bạn cũng có thể sử dụng 'izip_longest' – Marcin

+2

Được gọi là' zip_longest' cho người dùng python3. – zezollo

11

Tôi thích sử dụng zip(*iterable) (đó là đoạn mã bạn đang tìm kiếm) trong các chương trình của tôi như vậy:

def unzip(iterable): 
    return zip(*iterable) 

tôi thấy unzip dễ đọc hơn.

2

Đó là chỉ một cách khác để làm điều đó nhưng nó đã giúp tôi rất nhiều vì vậy tôi viết nó ở đây:

Có cấu trúc dữ liệu này:

X=[1,2,3,4] 
Y=['a','b','c','d'] 
XY=zip(X,Y) 

Hệ quả là:

In: XY 
Out: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')] 

Các nhiều cách để giải nén nó và quay trở lại bản gốc là cái này theo ý kiến ​​của tôi:

x,y=zip(*XY) 

Nhưng điều này trả về một tuple vì vậy nếu bạn cần một mảng, bạn có thể sử dụng:

xy=(list(x),list(y)) 
7
>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)] 
>>> tuple([list(tup) for tup in zip(*original)]) 
(['a', 'b', 'c', 'd'], [1, 2, 3, 4]) 

Cung cấp cho một tuple danh sách như trong câu hỏi.

list1, list2 = [list(tup) for tup in zip(*original)] 

Mở hai danh sách.

Các vấn đề liên quan