2012-04-30 8 views
6

thể trùng lặp:
Python: Retrieve items from a setCó cách nào để lấy một vật phẩm từ một bộ trong thời gian O (1) không?

Xét đoạn mã sau:

>>> item1 = (1,) 
>>> item2 = (2,) 
>>> s = set([item1, item2]) 
>>> s 
set([(2,), (1,)]) 
>>> new_item = (1,) 
>>> new_item in s 
True 
>>> new_item == item1 
True 
>>> new_item is item1 
False 

Vì vậy new_item là trong s vì nó tương đương với một trong các mục của nó, nhưng nó là một đối tượng khác.

Điều tôi muốn là nhận item1 từ s được cung cấp new_item nằm trong s.

Một giải pháp tôi đã đưa ra rất đơn giản nhưng không phải là rất hiệu quả:

def get_item(s, new_item): 
    for item in s: 
     if item == new_item: 
      return item 

>>> get_item(s, new_item) is new_item 
False 
>>> get_item(s, new_item) is item1 
True 

Một giải pháp khác có vẻ hiệu quả hơn nhưng thực tế không làm việc:

def get_item_using_intersection1(s, new_item): 
    return set([new_item]).intersection(s).pop() 

Cũng không phải cái này:

def get_item_using_intersection2(s, new_item): 
    return s.intersection(set([new_item])).pop() 

Do giao lộ hoạt động theo cách không xác định:

>>> get_item_using_intersection1(s, new_item) is new_item 
True 
>>> get_item_using_intersection1(s, new_item) is item1 
False 

>>> get_item_using_intersection2(s, new_item) is new_item 
True 
>>> get_item_using_intersection2(s, new_item) is item1 
False 

Nếu vấn đề này, tôi đang sử dụng Python 2.7 x64 trên Windows 7, nhưng tôi cần một giải pháp đa nền tảng.


Xin cảm ơn tất cả mọi người. Tôi đã đưa ra giải pháp tạm thời sau:

class SearchableSet(set): 

    def find(self, item): 
     for e in self: 
      if e == item: 
       return e 

sẽ được thay thế trong tương lai với các giải pháp sau đây (mà là rất không đầy đủ ngay bây giờ):

class SearchableSet(object): 

    def __init__(self, iterable=None): 
     self.__data = {} 
     if iterable is not None: 
      for e in iterable: 
       self.__data[e] = e 

    def __iter__(self): 
     return iter(self.__data) 

    def __len__(self): 
     return len(self.__data) 

    def __sub__(self, other): 
     return SearchableSet(set(self).__sub__(set(other))) 

    def add(self, item): 
     if not item in self: 
      self.__data[item] = item 

    def find(self, item): 
     return self.__data.get(item) 
+1

Nhưng ... "Giải pháp không hiệu quả" mà bạn đưa ra đã là tuyến tính. – kennytm

+0

Tôi nghĩ rằng anh ấy có nghĩa là * liên tục * thời gian –

+0

@KennyTM, cảm ơn bạn, tôi đã chỉnh sửa tiêu đề câu hỏi của mình. – utapyngo

Trả lời

12

Không sử dụng một set, sau đó . Chỉ cần sử dụng dict để ánh xạ một số giá trị cho chính nó. Trong trường hợp của bạn, nó maps:

d[item1] = item1 
d[item2] = item2 

Vì vậy, bất cứ điều gì đó là bằng item1 sẽ được tìm thấy trong d, nhưng giá trị là item1 riêng của mình. Và nó tốt hơn nhiều so với thời gian tuyến tính ;-)

P.S. Tôi hy vọng tôi hiểu ý định của câu hỏi của bạn một cách chính xác. Nếu không, xin vui lòng làm rõ nó.

+0

Cảm ơn bạn. Tôi biết nó có thể sử dụng 'dict' s nhưng tôi cũng biết rằng về mặt kỹ thuật nó có thể ở lại với 'set's (giả sử có một phương pháp nội bộ mà có thể tìm thấy một mục bằng băm). Bên cạnh đó, tôi không muốn viết lại mã cũ của mình vì tôi sử dụng các hoạt động thiết lập mạnh mẽ. – utapyngo

+7

@utapyngo: tốt hơn là viết lại mã cũ nếu mã không chính xác. 'set' chỉ đơn giản là không được thiết kế cho điều này - sử dụng một cấu trúc dữ liệu thích hợp hơn. –

+0

Làm thế nào để thực hiện việc inersection, union và sự khác biệt của các dicts như vậy trong thời gian tuyến tính? – utapyngo

2

Nếu bạn hoàn toàn cần O (1) tra cứu và bản sắc đối tượng (không chỉ là sự bình đẳng) hoạt động thiết lập nhanh (mà không cần phải tạo ra bộ mới mỗi lần bạn muốn làm bộ hoạt động), sau đó một cách công bằng phương pháp tiếp cận đơn giản là sử dụng cả hai a dictset. Bạn sẽ phải duy trì cả hai cấu trúc để giữ chúng trong đồng bộ, nhưng điều này sẽ cho phép bạn giữ O (1) truy cập (chỉ với một yếu tố không đổi lớn hơn).(Và có thể đây là những gì bạn đang hướng tới với "giải pháp tương lai của bạn hiện không hoàn chỉnh" trong bản chỉnh sửa của bạn.)

Tuy nhiên, bạn chưa đề cập đến khối lượng dữ liệu bạn đang làm việc hoặc loại vấn đề hiệu suất bạn đang gặp phải, nếu có. Vì vậy, tôi không thuyết phục bạn thực sự cần phải làm điều này. Có thể là dict khi cần thiết set tạo hoặc set với tra cứu tuyến tính, đã đủ nhanh.