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=}")
Asked By: Alessi 42

||

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.

Answered By: Barmar

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
Answered By: jsbueno
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.