Reputation: 61
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
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
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
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
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
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