2013-08-05 34 views
11

Cách nhanh nhất để xác định xem một dict có chứa khóa bắt đầu bằng một chuỗi cụ thể không? Chúng ta có thể làm tốt hơn tuyến tính không? Làm thế nào chúng ta có thể đạt được một hoạt động O (1) khi chúng ta chỉ biết bắt đầu một chìa khóa?Cách nhanh nhất để tìm kiếm python dict bằng một từ khóa

Đây là giải pháp hiện tại:

for key in dict.keys(): 
    if key.start_with(str): 
     return True 
return False 
+0

tôi nghi ngờ bạn có thể đạt được bất cứ điều gì tốt hơn là bạn không thể suy ra các hash của phím từ một phần của chìa khóa. Ngoài ra điều này lá phòng để mơ hồ nếu hai phím bắt đầu với cùng một tiền tố. – Hyperboreus

+0

Có cấu trúc dữ liệu có thể thực hiện điều này, nhưng chúng không có sẵn trong thư viện chuẩn của Python. Ví dụ: cây cố gắng hoặc cây tìm kiếm nhị phân. – delnan

+3

Vì câu hỏi là về tốc độ, tôi cảm thấy bắt buộc phải chỉ ra rằng 'cho khóa trong dict_:' là nhanh hơn nhiều so với 'cho khóa trong dict_.keys():', như sau này xây dựng một danh sách các phím. –

Trả lời

24

Nếu không có tiền xử lý dict, O(n) là tốt nhất bạn có thể làm. Nó không phải là phức tạp, mặc dù:

any(key.startswith(mystr) for key in mydict) 

(. Không sử dụng dictstr như tên biến, những người đã là tên của hai built-in functions)

Nếu bạn thể preprocess các dict, xem xét việc đặt các phím trong một cây tiền tố (aka trie). Thậm chí còn có Python implementation trong bài viết trên Wikipedia.

+0

Một trie là O (log N), không phải O (1). Nhưng nó gần như chắc chắn những gì bạn muốn ở đây. Đây là trường hợp mô hình khá nhiều cho cấu trúc dữ liệu. – abarnert

+0

@abarnert Không, trừ khi bạn đưa ra giả định kỳ lạ rằng độ dài chuỗi lớn nhất là logarit trong số chuỗi. Tra cứu trong một trie là tuyến tính theo chiều dài của khóa, và do đó độc lập với số chuỗi trong trie. – delnan

+0

@delnan: N không phải là số chuỗi, đó là số lượng ký hiệu riêng biệt. Nếu bạn có số biểu tượng nhỏ và tĩnh (ví dụ: với chuỗi ASCII), bạn có thể bỏ qua điều đó. Nếu bạn có một số lượng lớn các ký hiệu (ví dụ: Unicode tùy ý), bạn không thể. Hoặc bạn sẽ thực hiện tìm kiếm tuyến tính ở mỗi cấp độ Trie hoặc một lần đăng nhập N một lần. (Có, nó là _also_ tuyến tính trong độ dài của các chuỗi, và tôi đã bỏ qua điều đó ...) – abarnert

0

Bạn có thể đặt tất cả các tiền tố của các khóa được chèn vào dict, vì vậy đối với khóa foo bạn sẽ chèn f, fofoo. Bạn sẽ có O (1) tra cứu, nhưng bạn sẽ dành nhiều thời gian trên tiền xử lý (O (k), với k là chiều dài key), và lãng phí rất nhiều bộ nhớ:

def insert_with_prefixes(key, value, dict_): 
    prefixes = (key[:i+1] for i in xrange(len(key))) 
    dict_.update((prefix, value) for prefix in prefixes) 

Đối với sử dụng hàng ngày tôi sẽ đi (và tôi đi) với phương pháp trong câu trả lời arshajii's. Và tất nhiên, có trong tâm trí có thể nhiều va chạm với tiền tố ngắn (đây: "h"):

>>> a = {} 
>>> insert_with_prefixes('hello', 'world', a) 
>>> insert_with_prefixes('homo', 'sapiens', a) 
>>> a 
{'h': 'sapiens', 'hom': 'sapiens', 'homo': 'sapiens', 'ho': 'sapiens', 
'hel': 'world', 'hell': 'world', 'hello': 'world', 'he': 'world'} 
Các vấn đề liên quan