Reputation: 1796
Is there a fast way to find an object of a set, if I know how the hash was calculated?
I have the following class, uid
is an unique string (never used twice for different objects):
class Foo():
def __init__(self, uid):
self.uid = uid
self.__hash = hash(self.uid)
def __hash__(self):
return self.__hash
def __eq__(self, other):
return self.__hash == other.__hash
I have a set created with different uid
s:
foos = {Foo('a'), Foo('b'), Foo('c')}
I now wonder, if I want to have the item, which was initialized with b
, if there is a faster (and if possible more pythonic) way to get the element out of the sets than
b_object = next(foo for foo in foos if foo.uid == 'b')
since I could get hash_b = hash('b')
, which should provide somehow faster access, if the set is really huge (which is in my particular case obviously the case).
Upvotes: 1
Views: 1240
Reputation: 31339
I'm not sure what you're using this for, but you could do something like:
uid_to_foo = {foo.uid: foo for foo in foos}
# use 'uid_to_foo[some_foo.uid]' to find an instance fast
And now you get fast access to any Foo
instance through it's uid
.
Note that your current hash does not promise no collisions (although they are probably not likely).
You can even have this in the class itself:
class Foo():
# add class dictionary mapping uids to foos
uid_to_foo = {}
def __init__(self, uid):
self.uid = uid
self.__hash = hash(self.uid)
# add to class-level mapping
Foo.uid_to_foo[uid] = self
def __hash__(self):
return self.__hash
def __eq__(self, other):
return self.__hash == other.__hash
To create a mapping for every sub-class you can do something like (as asked in comments), using defaultdict
:
class Base():
# add class dictionary mapping uids to instances
uid_to_obj = defaultdict(dict)
def __init__(self, uid):
self.uid = uid
self.__hash = hash(self.uid)
# add specific sub-class mapping for each sub-class
Foo.uid_to_obj[type(self).__name__][uid] = self
def __hash__(self):
return self.__hash
def __eq__(self, other):
return self.__hash == other.__hash
The class-specific dictionaries are now obviously under Foo.uid_to_obj[type(self).__name__]
.
Upvotes: 1