Get item from set python
Question:
I have a set which contains objects which I have the __eq__
and __hash__
functions defined for.
I would like to be able to check if an object with the same hash is in the set and if it is in the set to return the object from the set as I need the reference to the object.
class SetObject():
def __init__(
self,
a: int,
b: int,
c: int
):
self.a = a
self.b = b
self.c = c
def __repr__(self):
return f"SetObject ({self.a} {self.b} {self.c}) (id: {id(self)}"
def __eq__(self, other):
return isinstance(other, SetObject)
and self.__hash__() == other.__hash__()
def __hash__(self):
# Hash only depends on a, b
return hash(
(self.a,self.b)
)
x = SetObject(1,2,3)
y = SetObject(4,5,6)
object_set = set([x,y])
print(f"{object_set=}")
z = SetObject(1,2,7)
print(f"{z=}")
if z in object_set:
print("Is in set")
# Get the object in set which is equal to z
for element in object_set:
if element == z:
print(element)
z = element
print(f"{z=}")
Answers:
Instead of using a set, use a dictionary where the keys and values are the same element. Then you can look use the value as a key and return the element.
x = SetObject(1,2,3)
y = SetObject(4,5,6)
object_set = dict([(x, x),(y, y)])
print(f"{object_set=}")
z = SetObject(1,2,7)
print(f"{z=}")
if z in object_set:
print("Is in set")
z = object_set[z]
print(f"{z=}")
If you want to simplify this, you could define a subclass of dict
that automatically makes the values the same as the keys.
As Alessi 42 puts in the comments, if you can, just use a dictionary, it will be simpler and way more efficient than this example.
The only way of retrieving an specific instance of a set is to perform some set-operations that would involve creating auxiliar sets:
def getinstance(set_, member):
set2 = set_ - set((member,))
return (set_ - set2).pop()
It is obvious that performance wise this is a lot worse than simply using a dictionary.
This simple class can be used to test the above function:
class IdInt(int):
count = 0
def __new__(cls, value):
instance = super().__new__(cls, value)
cls.count += 1
instance.id = cls.count
return instance
And on the interactive prompt:
In [29]: myset = set()
In [30]: a = IdInt(0)
In [31]: b = IdInt(0)
In [32]: myset.add(a)
In [33]: getinstance(myset, b) is a
Out[33]: True
In [34]: getinstance(myset, b) is b
Out[34]: False
I have a set which contains objects which I have the __eq__
and __hash__
functions defined for.
I would like to be able to check if an object with the same hash is in the set and if it is in the set to return the object from the set as I need the reference to the object.
class SetObject():
def __init__(
self,
a: int,
b: int,
c: int
):
self.a = a
self.b = b
self.c = c
def __repr__(self):
return f"SetObject ({self.a} {self.b} {self.c}) (id: {id(self)}"
def __eq__(self, other):
return isinstance(other, SetObject)
and self.__hash__() == other.__hash__()
def __hash__(self):
# Hash only depends on a, b
return hash(
(self.a,self.b)
)
x = SetObject(1,2,3)
y = SetObject(4,5,6)
object_set = set([x,y])
print(f"{object_set=}")
z = SetObject(1,2,7)
print(f"{z=}")
if z in object_set:
print("Is in set")
# Get the object in set which is equal to z
for element in object_set:
if element == z:
print(element)
z = element
print(f"{z=}")
Instead of using a set, use a dictionary where the keys and values are the same element. Then you can look use the value as a key and return the element.
x = SetObject(1,2,3)
y = SetObject(4,5,6)
object_set = dict([(x, x),(y, y)])
print(f"{object_set=}")
z = SetObject(1,2,7)
print(f"{z=}")
if z in object_set:
print("Is in set")
z = object_set[z]
print(f"{z=}")
If you want to simplify this, you could define a subclass of dict
that automatically makes the values the same as the keys.
As Alessi 42 puts in the comments, if you can, just use a dictionary, it will be simpler and way more efficient than this example.
The only way of retrieving an specific instance of a set is to perform some set-operations that would involve creating auxiliar sets:
def getinstance(set_, member):
set2 = set_ - set((member,))
return (set_ - set2).pop()
It is obvious that performance wise this is a lot worse than simply using a dictionary.
This simple class can be used to test the above function:
class IdInt(int):
count = 0
def __new__(cls, value):
instance = super().__new__(cls, value)
cls.count += 1
instance.id = cls.count
return instance
And on the interactive prompt:
In [29]: myset = set()
In [30]: a = IdInt(0)
In [31]: b = IdInt(0)
In [32]: myset.add(a)
In [33]: getinstance(myset, b) is a
Out[33]: True
In [34]: getinstance(myset, b) is b
Out[34]: False