2011-12-23 4 views
12

Если у меня есть объект, который сравнивается с элементом набора Python, но не является тем же самым объектом, существует ли разумный способ получить ссылку на объект в наборе? Вариант использования будет использовать набор для идентификации и обмена дублированными данными.Как получить доступ к элементу набора с использованием эквивалентного объекта?

Пример (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 

Как получить ссылку на a используя b и s? Я могу думать об одном способе, но я не уверен, что это не зависит от реализации, получаете ли вы a или b. EDIT: Это не работает, если s имеет более одного элемента; пересечение вполне естественно реализуется что-то вроде [x for x in smaller_set if x in larger_set]

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

Возможно, хорошим решением будет использовать Dict, который отображает каждый ключ к себе, а не множества.

+2

Если вам нужен определенный один из двух равных хешируемых объектов, кажется вероятным, что объекты не должны быть равными и/или хешируемыми. Зачем тебе это нужно? – delnan

+0

Я думаю, что ваши подозрения оправданы: pypy 1.7.0 и ironpython 3.0 оба (могут) возвращать False для вашего окончательного c. – DSM

+0

Я мог бы сэкономить память, изменив ссылки на равный объект на ссылки на один и тот же объект. –

ответ

3

Я нашел такой же вопрос в python-list: Get item from set. Существует умный ответ со ссылкой на get_equivalent(container, item) (Python recipe).

Хитрость заключается в создании объекта-обертки для объекта «ключ» и проверки наличия обертки в наборе с помощью оператора in. Если хэширование оболочки равно ключу, его метод __eq__ может получить доступ к объекту в наборе и сохранить ссылку на него. Важным моментом в обсуждении является то, что метод заданных элементов __eq__ должен возвращать NotImplemented для непризнанных типов, иначе обертка __eq__ не может быть вызвана.

1

Ваш случай использования звучит как прецедент для словарей. Используйте в качестве ключей атрибут объекта, который сравнивается с «чужим» объектом, а также как значения самих объектов.

Если это простой случай использования, и вы можете иметь линейную seartch, однако, вы могли бы сделать очевидное - это не было бы плохо:

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

Если вам нужно, что именно то, что вы ар спрашивать для (я могу удивиться некоторым случаям использования для этого) - wya to go - создать пользовательский класс словаря, который имеет набор как один из его членов, реализовать функции прокси-сервера для набора элементов, а также как в словаре, так и в методах набора, поддерживает синхронизацию как словаря, так и содержимого набора. Это займет много времени, чтобы реализовать право, но относительно просто.

Смежные вопросы