2011-01-15 31 views
6

Tôi có từ điển nhưbiểu Một dòng để ánh xạ từ điển khác

d = {'user_id':1, 'user':'user1', 'group_id':3, 'group_name':'ordinary users'} 

và "bản đồ" từ điển như:

m = {'user_id':'uid', 'group_id':'gid', 'group_name':'group'} 

Tất cả tôi muốn "thay thế" chìa khóa trong từ điển đầu tiên với các phím từ thứ hai (ví dụ: thay thế 'user_id' bằng 'uid', v.v.) Tôi biết rằng các khóa là không thay đổi và tôi biết cách thực hiện với câu lệnh 'if/else'.

Nhưng có thể có cách để làm điều đó trong một biểu thức dòng?

+0

Phiên bản python nào? – orlp

+0

uid là giá trị trong giây, không phải là khóa. Đầu ra bạn muốn xem là gì? –

Trả lời

15

chắc:

d = dict((m.get(k, k), v) for (k, v) in d.items()) 
+2

nó phải là 'cho (k, v) trong d.items' không phải' cho (k, v) trong d' – mouad

+0

Cố định. (Và được sửa lại, 'các mục' cần được gọi là phương thức.) –

+1

Đối với Python 2.x, sẽ thích hợp hơn khi sử dụng' d.iteritems() 'thay vì' d.items() '(nhưng điều này chỉ quan trọng đối với các từ điển thực sự lớn). –

5

Trong 3.x:

d = {m.get(key, key):value for key, value in d.items()} 

Nó hoạt động bằng cách tạo ra một từ điển mới, trong đó có tất cả các giá trị từ d và ánh xạ tới một chìa khóa mới. Chìa khóa được lấy ra như thế này: m[key] if m in key else key, nhưng sau đó với hàm .get mặc định (hỗ trợ các giá trị mặc định nếu khóa không tồn tại).

+0

+1 để thêm phiên bản v3 thành ngữ. –

0

Tại sao bạn muốn làm điều đó trong một dòng?

result = {} 
for k, v in d.iteritems(): 
    result[m.get(k, k)] = v 
+2

Bởi vì danh sách/dict/bất kỳ comprehensions là rất pythonesque và blazing nhanh? – orlp

+0

"Pythonic", nhưng có, khá nhiều điều đó. –

13

Hãy lấy mã tuyệt vời từ @karlknechtel và xem những gì nó làm:

>>> d = dict((m.get(k, k), v) for (k, v) in d.items()) 
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'} 

Nhưng làm thế nào nó hoạt động?

Để tạo từ điển, bạn có thể sử dụng chức năng dict(). Nó mong đợi một danh sách các bộ dữ liệu. Trong 3.x và> 2.7, bạn cũng có thể sử dụng tính năng đọc từ điển (xem câu trả lời của @nightcracker).

Hãy phân tích đối số của dict. Lúc đầu, chúng ta cần danh sách tất cả các mục trong m. Mỗi mục là một tuple trong định dạng (khóa, giá trị).

>>> d.items() 
[('group_id', 3), ('user_id', 1), ('user', 'user1'), ('group_name', 'ordinary users')] 

Cho một giá trị quan trọng k, chúng ta có thể nhận được giá trị quan trọng ngay từ m bằng cách làm m[k].

>>> k = 'user_id' 
>>> m[k] 
'uid' 

Thật không may, không phải tất cả các phím trong d cũng tồn tại trong m.

>>> k = 'user' 
>>> m[k] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
KeyError: 'user' 

Để làm việc xung quanh đó, bạn có thể sử dụng d.get(x, y), mà trả về d[x] nếu phím x tồn tại, hoặc giá trị mặc định y nếu nó không. Bây giờ, nếu một phím k từ d không tồn tại trong m, chúng tôi chỉ giữ nó, vì vậy mặc định là k.

>>> m.get(k, k). 
'user' 

Bây giờ chúng tôi sẵn sàng xây dựng danh sách các bộ dữ liệu để cung cấp cho dict(). Để tạo danh sách trong một dòng, chúng tôi có thể sử dụng list comprehension.

Để xây dựng một danh sách các hình vuông, bạn sẽ viết này:

>>> [x**2 for x in range(5)] 
[0, 1, 4, 9, 16] 

Trong trường hợp của chúng tôi, nó trông như thế này:

>>> [(m.get(k, k), v) for (k, v) in d.items()] 
[('gid', 3), ('uid', 1), ('user', 'user1'), ('group', 'ordinary users')] 

Đó là một mouthful, chúng ta hãy nhìn vào đó một lần nữa.

Hãy cho tôi một danh sách [...], trong đó bao gồm các bộ:

[(.., ..) ...] 

Tôi muốn một tuple cho mỗi mục x trong d:

[(.., ..) for x in d.items()] 

Chúng ta biết rằng mỗi mục là một tuple với hai thành phần, vì vậy chúng tôi có thể mở rộng thành hai biến số kv.

[(.., ..) for (k, v) in d.items()] 

Mọi bộ phận phải có khóa chính từ m là thành phần đầu tiên hoặc k nếu k không tồn tại trong m và giá trị từ d.

[(m.get(k, k), v) for (k, v) in d.items()] 

Chúng tôi có thể chuyển nó làm đối số cho dict().

>>> dict([(m.get(k, k), v) for (k, v) in d.items()]) 
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'} 

Có vẻ ổn! Nhưng hãy chờ, bạn có thể nói, @karlknechtel không sử dụng dấu ngoặc vuông.

Phải, anh ấy không sử dụng tính năng hiểu danh sách, nhưng là generator expression. Nói một cách đơn giản, sự khác biệt là việc hiểu danh sách xây dựng toàn bộ danh sách trong bộ nhớ, trong khi biểu thức trình tạo tính toán trên một mục tại một thời điểm. Nếu một danh sách trên phục vụ như là một kết quả trung gian, nó thường là một ý tưởng tốt để sử dụng một biểu thức máy phát điện. Trong ví dụ này, nó không thực sự tạo ra sự khác biệt, nhưng đó là một thói quen tốt để làm quen.

Các biểu thức máy phát điện tương đương trông như thế này:

>>> ((m.get(k, k), v) for (k, v) in d.items()) 
<generator object <genexpr> at 0x1004b61e0> 

Nếu bạn vượt qua một biểu thức máy phát điện như là đối số cho một hàm, bạn thường có thể bỏ qua các dấu ngoặc đơn bên ngoài. Cuối cùng, chúng tôi nhận được:

>>> dict((m.get(k, k), v) for (k, v) in d.items()) 
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'} 

Có rất nhiều điều trong một dòng mã. Một số người nói rằng điều này là không thể đọc được, nhưng một khi bạn đã quen với nó, việc kéo dài mã này qua nhiều dòng có vẻ không thể đọc được. Đừng lạm dụng nó. Danh sách hiểu và biểu thức máy phát điện là rất mạnh mẽ, nhưng với sức mạnh lớn đến trách nhiệm lớn. +1 cho một câu hỏi hay!

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