Ewokyeyey
Ewokyeyey

Reputation: 61

I can't remove a class object from a list

So I have this list (Sheep is a class i created, requiring one parameter):

list = [Sheep(2), Sheep(3), Sheep(3), Sheep(4), Sheep(4), Sheep(4), Sheep(5), Sheep(5), Sheep(5), Sheep(5), Sheep(6), Sheep(6), Sheep(6), Sheep(7), Sheep(7), Sheep(8)]

However, when I try to remove Sheep(2) (list.remove(Sheep(2)) from the list, it returns ValueError: list.remove(x): x not in list

How do I fix this?

Upvotes: 4

Views: 1316

Answers (5)

Iain Shelvington
Iain Shelvington

Reputation: 32244

To test for membership in a python list with a custom class you must provide an equality (__eq__) method

class Sheep:

    def __init__(self, x):
        self.x = x

    def __eq__(self, other):
        assert isinstance(other, Sheep)
        return self.x == other.x

Now you can create instances of your class with the same "x" and they will be members of your list

foo = [Sheep(2), Sheep(3), Sheep(3), Sheep(4), Sheep(4), Sheep(4), Sheep(5), Sheep(5), Sheep(5), Sheep(5), Sheep(6), Sheep(6), Sheep(6), Sheep(7), Sheep(7), Sheep(8)]
print(Sheep(2) in foo)  # True

And you should be able to remove them too

foo.remove(Sheep(2))
print(foo)  # [Sheep(3), Sheep(3), Sheep(4), Sheep(4), Sheep(4), Sheep(5), Sheep(5), Sheep(5), Sheep(5), Sheep(6), Sheep(6), Sheep(6), Sheep(7), Sheep(7), Sheep(8)]

Upvotes: 4

Joshua Fox
Joshua Fox

Reputation: 19655

The two Sheep(2)s are different objects.

To let the the first Sheep(2) be found by comparing it to the second one, define equality on your Sheep. Then

class Sheep: 
    def __init__(self, camouflage_score): 
       self.camo = camouflage_score          

    def __eq__(self, other):
        return other and self.camo == other.camo

Upvotes: 2

han solo
han solo

Reputation: 6590

You can remove the other instances using a list comprehension by checking value like,

>>> list = [Sheep(2), Sheep(3), Sheep(3), Sheep(4), Sheep(4), Sheep(4), Sheep(5), Sheep(5), Sheep(5), Sheep(5), Sheep(6), Sheep(6), Sheep(6), Sheep(7), Sheep(7), Sheep(8)]
>>> newl = [x for x in list if x.camo != 2] # will remove all Sheep with camo value == 2

For removing only one instance with the value, you can do something like,

>>> for idx, sheep in enumerate(list[:]):
...   if sheep.camo == 3:
...     list.pop(idx)
...     break

But i'd recommend you implement the __eq__ method in your Sheep class and just do

>>> list.remove(Sheep(3))

And now the new list will be like,

>>> newl
[Sheep(3), Sheep(3), Sheep(4), Sheep(4), Sheep(4), Sheep(5), Sheep(5), Sheep(5), Sheep(5), Sheep(6), Sheep(6), Sheep(6), Sheep(7), Sheep(7), Sheep(8)]

Upvotes: 1

Mehrdad Pedramfar
Mehrdad Pedramfar

Reputation: 11073

Look at this:

class Sheep: 
    def __init__(self,v): 
        self.v = v 

When you create an instance:

In [3]: Sheep(1)                                                                                                                                                                                                   
Out[3]: <__main__.Sheep at 0x7fa5a7614550>

In [4]: Sheep(1)                                                                                                                                                                                                   
Out[4]: <__main__.Sheep at 0x7fa5a49bf4a8>

Look carefully at 0x7fa5a7614550 and 0x7fa5a49bf4a8, They are different:

In [5]: Sheep(1) == Sheep(1)                                                                                                                                                                                       
Out[5]: False

That is because of creating instance, each time you create an instance with same value, it does not mean that they are same.

but you can do something like this:

In [6]: Sheep(1).v == Sheep(1).v                                                                                                                                                                                   
Out[6]: True

so if you want to remove item with v=2, you can do this:

list_of_sheeps = [Sheep(2), Sheep(3), Sheep(3), Sheep(4), Sheep(4), Sheep(4), Sheep(5), Sheep(5), Sheep(5), Sheep(5), Sheep(6), Sheep(6), Sheep(6), Sheep(7), Sheep(7), Sheep(8)]

new_list = [i for i in list_of_sheeps if i.v != 2] # v is the name of inner field. (self.v)

Then the new_list will be your desired result without Sheep(2).

or using filter:

new_list = list(filter(lambda x:x.v != 2, list_of_sheeps))

Note that:

Do NOT USE list as a name of variable. list is built-in name in python, you will override its own functionality.

Upvotes: 1

Irfanuddin
Irfanuddin

Reputation: 2605

You can use index to remove your objects.

x = object()
y = object()
array = [x, y]
array.pop(0)
# Using the del statement
del array[0]

Upvotes: 1

Related Questions