2011-12-23 13 views
12

Jeśli mam obiekt, który jest porównywalny do elementu zestawu Python, ale nie jest tym samym obiektem, czy istnieje rozsądny sposób na uzyskanie odniesienia do obiektu w zestawie? Przypadkiem użycia byłoby użycie zestawu do identyfikacji i udostępniania zduplikowanych danych.Jak uzyskać dostęp do elementu zestawu za pomocą równoważnego obiektu?

Przykład (Python 2.7):

>>> a = "This is a string" 
>>> b = "This is a string" 
>>> a is b 
False 
>>> a == b 
True 
>>> s = set((a,)) 
>>> b in s 
True 

Jak uzyskać odniesienie do a użyciu b i s? Mogę wymyślić jeden sposób, ale nie jestem pewien, czy to nie zależy od implementacji, czy otrzymasz a lub b. EDYCJA: To nie działa, gdy s ma więcej niż jeden element; skrzyżowanie jest dość naturalnie realizowane coś [x for x in smaller_set if x in larger_set]

>>> for x in set((b,)).intersection(s): c = x 
... 
>>> c is a 
True 

Być dobrym obejście byłoby użyć dict, który mapuje każdy klucz do siebie, zamiast zestawu.

+2

Jeśli potrzebujesz konkretnego jednego z dwóch równych, możliwych do zahartowania obiektów, wydaje się prawdopodobne, że obiekty nie będą równe i/lub nieczytelne. Dlaczego tego potrzebujesz? – delnan

+0

Myślę, że twoje podejrzenia są uzasadnione: pypy 1.7.0 i ironpython 3.0 oba (puszka) zwracają False dla twojego końcowego c jest a. – DSM

+0

Mógłbym zaoszczędzić pamięć, zmieniając odniesienia do równego obiektu na odniesienia do tego samego obiektu. –

Odpowiedz

3

Znalazłem podobne pytanie na python-liście: Get item from set. Jest sprytna odpowiedź w odniesieniu do get_equivalent(container, item) (Python recipe).

Sztuką jest skonstruowanie obiektu opakowania dla obiektu "kluczowego" i sprawdzenie, czy opakowanie znajduje się w zestawie przy użyciu operatora in. Jeśli opakowujące hashy są równe kluczowi, jego metoda __eq__ może uzyskać dostęp do obiektu w zestawie i zapisać odniesienie do niego. Ważnym punktem dyskusji jest to, że metoda set elementów musi zwracać NotImplemented dla nierozpoznanych typów, w przeciwnym razie może nie zostać wywołana wrappera __eq__.

1

Twój przypadek użycia brzmi tak, jak w przypadku słowników. Używaj jako kluczy atrybutu porównywalnego obiektu do "obcego" obiektu i jako wartości samych pożądanych obiektów.

Jeśli jest to prosta sprawa używania i można mieć liniowy seartch jednak można zrobić, co oczywiste - nie byłoby źle:

def get_equal(in_set, in_element): 
    for element in in_set: 
     if element == in_element: 
      return element 
    return None 

Jeśli potrzebujesz co dokładnie to, czego ar prosząc dla (mogę się zastanawiać nad niektórymi przypadkami użycia) - wya, aby przejść, polega na utworzeniu niestandardowej klasy słownika, która ma zestaw jako jeden z jej członków, zaimplementowania metod proxy w zestawie członków oraz w metodach słownikowych i ustawionych, utrzymuje synchronizację zarówno słownika, jak i ustawionej zawartości. Byłoby to czasochłonne wdrożenie, ale stosunkowo proste.