2010-07-12 63 views
20

Tôi vừa học về khả năng hiểu danh sách, đây là một cách nhanh chóng để lấy dữ liệu trong một dòng mã. Nhưng có điều gì đó làm tôi khó chịu.Đọc danh sách Python cho từ điển trong từ điển?

Trong thử nghiệm của tôi, tôi có loại từ điển bên trong danh sách:

[{'y': 72, 'x': 94, 'fname': 'test1420'}, {'y': 72, 'x': 94, 'fname': 'test277'}] 

Danh sách hiểu s = [ r for r in list if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ] hoạt động hoàn hảo trên đó (đó là, trên thực tế, kết quả của dòng này)

Dù sao , Sau đó tôi nhận ra rằng tôi không thực sự sử dụng một danh sách trong dự án khác của tôi, tôi đang sử dụng một từ điển. Cũng giống như vậy:

{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'}} 

Bằng cách đó tôi chỉ có thể chỉnh sửa từ điển của tôi với var['test1420'] = ...

Nhưng danh sách comprehensions không làm việc trên đó! Và tôi không thể chỉnh sửa danh sách theo cách này vì bạn không thể chỉ định một chỉ mục như thế.

Có cách nào khác không?

+1

Việc hiểu danh sách có thể thật tuyệt, nhưng đừng quá tải. Không có quy tắc kiên định chống lại sự hiểu biết khổng lồ, nhưng đối với những gì đáng giá, Hướng dẫn kiểu Python của Google đề xuất chống lại bất kỳ điều gì quá phức tạp: http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=List_Comprehensions#List_Comprehensions –

Trả lời

36

Bạn có thể làm điều này:

s = dict([ (k,r) for k,r in mydict.iteritems() if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ]) 

này có một dict như bạn chỉ định và trả về một dict 'lọc'.

+0

Hoạt động theo cách tương tự như giải pháp của Tryptich, nhưng việc sử dụng iteritems thực sự nhanh hơn. Cảm ơn! – skerit

+0

bạn có thể làm điều này thậm chí nhanh hơn nếu bạn biến '[]' thành '()' như dict có thể lấy một máy phát làm đối số (nếu biểu thức máy phát là đối số duy nhất như trong trường hợp này, ngay cả '()' có thể bên trái) –

8

Nếu dct

{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'}, 
'test277': {'y': 72, 'x': 94, 'fname': 'test277'},} 

Có lẽ bạn đang tìm kiếm cái gì đó như:

[ subdct for key,subdct in dct.iteritems() 
    if 92<subdct['x']<95 and 70<subdct['y']<75 ] 

Một tính tinh vi nhỏ là Python cho phép bạn bất bình đẳng chuỗi:

92<dct[key]['x']<95 

thay vì

if r['x'] > 92 and r['x'] < 95 

Lưu ý rằng ở trên tôi đã viết một danh sách hiểu, vì vậy bạn lấy lại một danh sách (trong trường hợp này, của dicts).

Trong Python3 có những điều như dict comprehensions cũng như:

{ n: n*n for n in range(5) } # dict comprehension 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 

Trong python2 tương đương sẽ là

dict((n,n*n) for n in range(5)) 

Tôi không chắc chắn nếu bạn đang tìm kiếm một danh sách các dicts hoặc một dict của dicts, nhưng nếu bạn hiểu các ví dụ trên, thật dễ dàng để sửa đổi câu trả lời của tôi để có được những gì bạn muốn.

0

Bạn có thể nhận danh sách các giá trị của từ điển d với d.values(). Việc hiểu danh sách của bạn nên hoạt động bằng cách sử dụng điều đó, mặc dù tôi không rõ chính xác bạn muốn kết quả đầu ra là gì.

2

Âm thanh như bạn muốn một cái gì đó như:

my_dict = {'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'}, 
      'test277' : {'y': '072', 'x': '094', 'fname': 'test277'}} 


new_dict = dict((k,v) for k,v in my_dict.items() 
        if 92 < int(v['x']) < 95 and 70 < int(v['y']) < 75) 

Một số lưu ý về mã này:

  1. Tôi đang sử dụng một biểu thức máy phát điện thay vì một sự hiểu biết danh sách
  2. Python cho phép bạn kết hợp bất bình đẳng kiểm tra dưới dạng low < value < high
  3. Hàm tạo dict() có thể lặp lại của bộ khóa/giá trị để tạo một số từ điển
+0

Công trình này trông giống như giải pháp của adamk. Tuy nhiên, bằng cách sử dụng iteritems là khá nhanh hơn một chút so với này. Cả hai er chậm hơn so với việc hiểu danh sách thông thường, mặc dù: P Cảm ơn lời khuyên kết hợp! – skerit

0

Có cách nào khác không?

Tại sao không xem xét việc sử dụng một số đối tượng nhẹ?

Bạn có thể vẫn sử dụng tính năng hiểu danh sách để thu thập hoặc lọc các đối tượng và đạt được độ rõ ràng/khả năng mở rộng.

>>> class Item(object): 
...  def __init__(self, x, y, name): 
...   self.x = x 
...   self.y = y 
...   self.name = name 
... 
>>> list_items = [] 
>>> list_items.append(Item(x=70, y=60, name='test1420'))       
>>> list_items.append(Item(x=94, y=72, name='test277'))       
>>> items_matching = [item for item in list_items 
         if 92 < item.x < 95 and 70 < item.y < 75] 
>>> for item in items_matching: 
...  print item.name 
... 
test277 
>>> first_item = items_matching[0] 
>>> first_item.x += 50 
>>> first_item.x 
144 
Các vấn đề liên quan