2012-06-22 35 views
12

Tôi có một danh sách giống như thế này:Python - ngã ​​tư giữa một danh sách và chìa khóa của một cuốn từ điển

l1 = ['200:200', '90:728'] 

Tôi có một cuốn từ điển đó trông như thế này:

d1 = {'200:200':{'foo':'bar'},'300:300':{'foo':'bar'}} 

tôi cần phải nhận được lọc ra các dictioary, nơi chỉ có các phím trong l1. Các dict sẽ trông như thế này:

result = {'200:200':{'foo':'bar'}} 

Thực chất là một giao điểm của danh sách và các phím của một dict khi trả về phần phụ của dict.

Làm cách nào để thực hiện điều này một cách hiệu quả khi thời gian là vấn đề đối với một nhóm lớn?

Cảm ơn

Trả lời

23

Bạn có thể sử dụng đoạn mã sau:

keys = set(l1).intersection(set(d1.keys())) 
result = {k:d1[k] for k in keys} 

EDIT: Như bình luận đề nghị bạn có thể thay thế dòng đầu tiên với, bằng Python 2.x:

keys = set(l1).intersection(d1) 

Và bằng Python 3.x:

keys = d1.keys() & l1 
+0

Lưu ý rằng trong 3.x, chế độ xem từ điển được đặt tương tự, vì vậy bạn không cần phải bọc nó trong 'set()'. Trong thực tế, trong 3.x, toàn bộ dòng trên cùng có thể là 'keys = d1.keys() & l1'. –

+1

@Lattyware bạn không cần phải đúc nó thành một bộ trong 2.x hoặc – jamylak

+4

Thậm chí không cần phím(), 'bộ (l1) .intectionection (d1)' – georg

0

Bạn có thể sử dụng danh sách hiểu trong constructor dict:

result = dict([(k,d1[k]) for k in l1 if k in d1]) 

Nếu bạn đang lo lắng về việc loại bỏ các phím trùng lặp, hãy l1 thành một tập đầu tiên:

result = dict([(k,d1[k]) for k in set(l1) if k in d1]) 
+0

Khoá có thể không nằm trong 'd1'. Điều này sẽ không hoạt động. –

+0

Cũng lưu ý bạn có thể làm biểu thức trình tạo dict như trong giải pháp của tôi. Vì vậy, '{k: v cho k, v trong arr}'. Điều này thậm chí có lợi ích của việc đối phó với các bản sao. – JPvdMerwe

+0

@JPvdMerwe Đó là một hiểu biết dict, không phải là một biểu thức máy phát điện dict - biểu thức máy phát điện là lười biếng, một hiểu dict không phải là. –

4

Trong 3.x, điều này có thể đơn giản như:

>>> {k: d1[k] for k in (d1.keys() & l1)} 
{'200:200': {'foo': 'bar'}} 

Dưới 2.7, bạn có thể sử dụng dict.viewkeys() để tái tạo chức năng này:

>>> {k: d1[k] for k in (d1.viewkeys() & l1)} 
{'200:200': {'foo': 'bar'}} 

Theo phiên bản cũ của 2.x, đó là một chút dài dòng hơn:

>>> {k: d1[k] for k in (set(d1).intersection(l1))} 
{'200:200': {'foo': 'bar'}} 
+0

Tôi đã kiểm tra tài liệu. Có vẻ như 'viewkeys()' có sẵn trong 2.7, không chỉ 2.7.3. Nó xuất hiện trong bản sao của tôi về Python 2.7.1 – JPvdMerwe

+0

@JPvdMerwe Tốt để biết, cập nhật. –

3

Không chắc về mỗi màn trình diễn giải pháp, nhưng tôi sẽ làm:

{k: v for k, v in d1.items() if k in l1} 
+2

Điều này sẽ làm việc ngay cả khi một thành viên của l1 không phải là một khóa trong d1, mà nhiều người khác sẽ thất bại trên. –

0

Xác định hiệu quả. Dù sao thì đây là những gì tôi sẽ làm. Nếu nó quá chậm, tôi có thể chuyển nó sang Cython.

s1 = set(l1) 
s2 = set(d1.keys()) 
s3 = s1 & s2 
# now you can access d1 using only keys in s3, or construct a new dict if you like 
d2 = dict([(k,d1[k]) for k in s3]) 
0

Nếu phân bổ bộ nhớ và deallocation khiến quy trình này mất quá nhiều thời gian, công cụ lặp lại để giải cứu.

import itertools 
result = {dict_key:d1[dict_key] for dict_key in itertools.ifilter(lambda list_item: list_item in d1, l1) } 

Điều này không cần thiết cấp phát bộ nhớ cho toàn bộ bộ sưu tập mới và l1 có thể dễ dàng là người lặp thay vì danh sách.

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