Hello, all.
Is it possible to get an object out of a set() given another object that has the same hash code and equality (__hash__() and __eq__() return the same)?
You can't do this with Java Sets either and I've needed it on multiple occasions. Doesn't it seem like it would be useful? Consider:
class Person: def __init__(self, id, name): self.id = id self.name = name
def __hash__(self): return self.id
def __eq__(self, other): return self.id == other.id
people = set( [Person(1, 'Joe'), Person(2, 'Sue')] ) ... p = people.get_equivalent(2) #method doesn't exist as far as I know print p.name #prints Sue
I'm not sure if the above code compiles but I hope you get the idea. Is it possible? Much Thanks. - Cruxic
Cruxic's gravatar image asked Mar 7 2008 at 19:13 in Python by Cruxic

7 Answers

[Cruxic]
Yes, but it requires an indirect approach. http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/499299
Raymond
Raymond Hettinger's gravatar image answered Mar 7 2008 at 19:20 by Raymond Hettinger
def get_equivalent(test, container):
for p in container:
if p == test:
return p
hth,
Alan Isaac
#example (note change in __eq__ to match your case; fix if nec)
class Person:
def __init__(self, id, name):
self.id = id
self.name = name
def __hash__(self):
return self.id
def __eq__(self, other):
return self.id == other
people = set( [Person(1, 'Joe'), Person(2, 'Sue')] )
get_equivalent(2,people)
Alan Isaac's gravatar image answered Mar 8 2008 at 15:32 by Alan Isaac
That's a clever work around. Thanks, Raymond. Clearly you had a need for this. Do you feel it's a common need that should be submitted as a Python feature request? To me it seems like such a simple thing that would increase the general utility of the set class. I suppose I could start another thread like "feature request: New method for set - get_equivalent".
Cruxic's gravatar image answered Mar 8 2008 at 16:25 by Cruxic
That works fine for small data sets but my goal is to avoid a linear search, instead leveraging the O(1) lookup time for a hash based set.
Cruxic's gravatar image answered Mar 8 2008 at 16:28 by Cruxic
Glad you liked the recipe. :-) FWIW, it is not specific to sets. The recipe works with any container including dictionaries and lists. The approach is easily extended to any situation with equality testing. For example, it can be used with list.remove(x) to find the identity of the removed object.
Long ago, I rejected adding get_equivalent() to the set API. The existing API has a near zero learning curve and it would be nice to keep it that way.
For most use cases, the obvious, explicit approach is better. Just make a dictionary where the value is the canonical representative of the equivalence class:
>>> d = {1:1, 2:2, 3:3} >>> d[2.0] 2
The intern() builtin uses this approach:
interned = {} def intern(s): if s in interned: return interned[s] interned[s] = s return s
Raymond
Raymond Hettinger's gravatar image answered Mar 8 2008 at 19:15 by Raymond Hettinger
If you've seen it before, and have the old one, return the old one. Do I have this straight?
castironpigmail.com's gravatar image answered Mar 8 2008 at 20:27 by castironpigmail.com
F(!
Raymond Hettinger's gravatar image answered Mar 9 2008 at 17:36 by Raymond Hettinger