In Python, how can I remove an object from a list of objects? Like this:
x = object()
y = object()
array = [x, y]
# Remove x
I've tried array.remove() but it only works with a value, not a specific location in the array. I need to be able to delete the object by addressing its position (remove array[0]).
There are various ways to delete an object from a list:
my_list = [1,2,4,6,7]
del my_list[1] # Removes index 1 from the list
print my_list # [1,4,6,7]
my_list.remove(4) # Removes the integer 4 from the list, not the index 4
print my_list # [1,6,7]
my_list.pop(2) # Removes index 2 from the list
In your case the appropriate method to use is pop, because it takes the index to be removed:
x = object()
y = object()
array = [x, y]
array.pop(0)
# Using the del statement
del array[0]
del array[0]
where 0 is the index of the object in the list (there is no array in python)
If you want to remove multiple object from a list. There are various ways to delete an object from a list
Try this code. a is list with all object, b is list object you want to remove.
example :
a = [1,2,3,4,5,6]
b = [2,3]
for i in b:
if i in a:
a.remove(i)
print(a)
the output is [1,4,5,6]
I hope, it will work for you
You could try this to dynamically remove an object from an array without looping through it? Where e and t are just random objects.
>>> e = {'b':1, 'w': 2}
>>> t = {'b':1, 'w': 3}
>>> p = [e,t]
>>> p
[{'b': 1, 'w': 2}, {'b': 1, 'w': 3}]
>>>
>>> p.pop(p.index({'b':1, 'w': 3}))
{'b': 1, 'w': 3}
>>> p
[{'b': 1, 'w': 2}]
>>>
You can remove a string from an array like this:
array = ["Bob", "Same"]
array.remove("Bob")
if you wanna remove the last one just do your_list.pop(-1)
if you wanna remove the first one your_list.pop(0) or any index you wish to remove
If you know the array location you can can pass it into itself. If you are removing multiple items I suggest you remove them in reverse order.
#Setup array
array = [55,126,555,2,36]
#Remove 55 which is in position 0
array.remove(array[0])
If we have an object x (e.g. an instance of some class X) that's in a list of other objects of the same type, we can simply directly remove it using list.remove(), provided the class has __eq__ properly implemented (this is already the case for built-in object types, but for custom classes always remember to implement the eq dunder function):
class X():
def __init__(self, value=None):
self.a = value
def __eq__(self, other):
if not hasattr(other, 'a'):
return False
return self.a == other.a
x = X(4)
y = X(10)
z = X(9)
my_list = [x,y,z]
print([e.a for e in a])
# prints [4, 10, 9]
my_list.remove(x)
print([e.a for e in a])
# prints [10, 9]
Related
I run into a problem when unpacking a tuple. I want the first value to be appended to a list and a second assigned to a variable. For example:
list = []
tuple = (1, 2)
list.append, variable = tuple
But this raises an exception since I am assigning to a bultin and not actually calling in. Is that possible in Python? Or even a simpler operation such as:
a, b = 5, 4
tuple = (1, 2)
a+, b = tuple
to yield a = 6, b = 2.
There's no brief syntax to allow this. However, here's a class that creates a wrapper around a list, so that assigning to an append attribute really calls the underlying list's append method. This could be useful if you have a lot of values to append to the list.
class Appender:
def __init__(self, lst):
self.lst = lst
# The rare write-only property
append = property(None, lambda self, v: self.lst.append(v))
values = []
value_appender = Appender(values)
value_appender.append, b = (1,2)
assert values == [1]
Perhaps simpler, a subclass of list with a similar property:
class Appendable(list):
take = property(None, lambda self, v: self.append(v))
values = Appendable()
values.take, b = (1, 2)
assert values == [1]
append is a method on the builtin list type. Python allows tuple unpacking into variables in one line as a convenience, but it won't decide to call the append method with part of your tuple as an argument. Just write your code on multiple lines, that will help make it easier to read too.
my_list = []
my_tuple = (1, 2)
a, b = my_tuple
my_list.append(a)
Technically yes you could do it in a single line, but I wouldn't.
l = []
a = (1,2)
l[:0], b = [[x] if c == 0 else x for c,x in enumerate(a)]
>>> l
[1]
>>> b
2
You can use the map function on the append method for the list.
>>> a = (6,7)
>>> b = [1,2,3,4,5]
>>> list(map(b.append, a))
[None, None]
>>> b
[1, 2, 3, 4, 5, 6, 7]
I am not really sure what the list() does in this statement but it seems to work.
I imagine this is one in a very long list of questions from people who have inadvertantly created references in python, but I've got the following situation. I'm using scipy minimize to set the sum of the top row of an array to 5 (as an example).
class problem_test:
def __init__(self):
test_array = [[1,2,3,4,5,6,7],
[4,5,6,7,8,9,10]]
def set_top_row_to_five(x, array):
array[0] = array[0] + x
return abs(sum(array[0]) - 5)
adjustment = spo.minimize(set_top_row_to_five,0,args=(test_array))
print(test_array)
print(adjustment.x)
ptest = problem_test()
However, the optimization is altering the original array (test_array):
[array([-2.03, -1.03, -0.03, 0.97, 1.97, 2.97, 3.97]), [4, 5, 6, 7, 8, 9, 10]]
[-0.00000001]
I realize I can solve this using, for example, deepcopy, but I'm keen to learn why this is happening so I don't do the same in future by accident.
Thanks in advance!
Names are references to objects. What is to observe is whether the objects (also passed in an argument) is modified itself or a new object is created. An example would be:
>>> l1 = list()
>>> l2 = l1
>>> l2.append(0) # this modifies object currently reference to by l1 and l2
>>> print(l1)
[0]
Whereas:
>>> l1 = list()
>>> l2 = list(l1) # New list object has been created with initial values from l1
>>> l2.append(0)
>>> print(l1)
[]
Or:
>>> l1 = list()
>>> l2 = l1
>>> l2 = [0] # New list object has been created and assigned to l2
>>> l2.append(0)
>>> print(l1)
[]
Similarly assuming l = [1, 2, 3]:
>>> def f1(list_arg):
... return list_arg.reverse()
>>> print(f1, l)
None [3, 2, 1]
We have just passed None returned my list.reverse method through and reversed l (in place). However:
>>> def f2(list_arg):
... ret_list = list(list_arg)
... ret_list.reverse()
... return ret_list
>>> print(f2(l), l)
[3, 2, 1] [1, 2, 3]
Function returns a new reversed object (initialized) from l which remained unchanged (NOTE: in this exampled built-in reversed or slicing would of course make more sense.)
When nested, one must not forget that for instance:
>>> l = [1, 2, 3]
>>> d1 = {'k': l}
>>> d2 = dict(d1)
>>> d1 is d2
False
>>> d1['k'] is d2['k']
True
Dictionaries d1 and d2 are two different objects, but their k item is only one (and shared) instance. This is the case when copy.deepcopy might come in handy.
Care needs to be taken when passing objects around to make sure they are modified or copy is used as wanted and expected. It might be helpful to return None or similar generic value when making in place changes and return the resulting object when working with a copy so that the function/method interface itself hints what the intention was and what is actually going on here.
When immutable objects (as the name suggests) are being "modified" a new object would actually be created and assigned to a new or back to the original name/reference:
>>> s = 'abc'
>>> print('0x{:x} {}'.format(id(s), s))
0x7f4a9dbbfa78 abc
>>> s = s.upper()
>>> print('0x{:x} {}'.format(id(s), s))
0x7f4a9c989490 ABC
Note though, that even immutable type could include reference to a mutable object. For instance for l = [1, 2, 3]; t1 = (l,); t2 = t1, one can t1[0].append(4). This change would also be seen in t2[0] (for the same reason as d1['k'] and d2['k'] above) while both tuples themselves remained unmodified.
One extra caveat (possible gotcha). When defining default argument values (using mutable types), that default argument, when function is called without passing an object, behaves like a "static" variable:
>>> def f3(arg_list=[]):
... arg_list.append('x')
... print(arg_list)
>>> f3()
['x']
>>> f3()
['x', 'x']
Since this is often not a behavior people assume at first glance, using mutable objects as default argument value is usually better avoided.
Similar would be true for class attributes where one object would be shared between all instances:
>>> class C(object):
... a = []
... def m(self):
... self.a.append('x') # We actually modify value of an attribute of C
... print(self.a)
>>> c1 = C()
>>> c2 = C()
>>> c1.m()
['x']
>>> c2.m()
['x', 'x']
>>> c1.m()
['x', 'x', 'x']
Note what the behavior would be in case of class immutable type class attribute in a similar example:
>>> class C(object):
... a = 0
... def m(self):
... self.a += 1 # We assign new object to an attribute of self
... print(self.a)
>>> c1 = C()
>>> c2 = C()
>>> c1.m()
1
>>> c2.m()
1
>>> c1.m()
2
All the fun details can be found in the documentation: https://docs.python.org/3.6/reference/datamodel.html
In python objects such as lists are passed by reference. Assignment with the = operator assigns by reference. So this function:
def modify_list(A):
A = [1,2,3,4]
Takes a reference to list and labels it A, but then sets the local variable A to a new reference; the list passed by the calling scope is not modified.
test = []
modify_list(test)
print(test)
prints []
However I could do this:
def modify_list(A):
A += [1,2,3,4]
test = []
modify_list(test)
print(test)
Prints [1,2,3,4]
How can I assign a list passed by reference to contain the values of another list? What I am looking for is something functionally equivelant to the following, but simpler:
def modify_list(A):
list_values = [1,2,3,4]
for i in range(min(len(A), len(list_values))):
A[i] = list_values[i]
for i in range(len(list_values), len(A)):
del A[i]
for i in range(len(A), len(list_values)):
A += [list_values[i]]
And yes, I know that this is not a good way to do <whatever I want to do>, I am just asking out of curiosity not necessity.
You can do a slice assignment:
>>> def mod_list(A, new_A):
... A[:]=new_A
...
>>> liA=[1,2,3]
>>> new=[3,4,5,6,7]
>>> mod_list(liA, new)
>>> liA
[3, 4, 5, 6, 7]
The simplest solution is to use:
def modify_list(A):
A[::] = [1, 2, 3, 4]
To overwrite the contents of a list with another list (or an arbitrary iterable), you can use the slice-assignment syntax:
A = B = [1,2,3]
A[:] = [4,5,6,7]
print(A) # [4,5,6,7]
print(A is B) # True
Slice assignment is implemented on most of the mutable built-in types. The above assignment is essentially the same the following:
A.__setitem__(slice(None, None, None), [4,5,6,7])
So the same magic function (__setitem__) is called when a regular item assignment happens, only that the item index is now a slice object, which represents the item range to be overwritten. Based on this example you can even support slice assignment in your own types.
I'm trying to filter an object returning a list of a specific attribute. Look what I've tried:
class Foo:
def __init__(self,a,b):
self.a = a
self.b = b
x = Foo(1,2)
y = Foo(1,3)
z = Foo(2,4)
result = filter(lambda f: f.b if f.a == 1 else None, [x,y,z])
print(list(result))
I was expecting a list like this [2, 3], but It returns me a list of foo objects. Is there a way to do it using just filter other function? I'd like to avoid using map and filter, for example.
You can use a list comprehension
result = [i.b for i in [x,y,z] if i.a == 1]
Using filter it would take two steps: one to filter out the objects where i.a != 1 and the second to pull the .b out of each object (which would require map).
I need to print the elements of a list in the form of a set. So if I have the list [1,2,3] the print statement needs to return {1,2,3}.
Here it is
s=[1,2,3]
print("{"+str(s)[1:-1]+"}")
Here's one way (where x is your list):
>>> print("{" + ', '.join(str(item) for item in x) + "}")
{1, 2, 3}
If you want a set, why not turn the list into a set? With x being your list:
>>> x=[1,2,3]
>>> x_set=set(x)
>>> print(x_set)
{1, 2, 3}
It's noteworthy that sets are not ordered and cannot contain duplicates. (But then again what is the benefit of printing something to look 'like' a set, but is not?)
>>> x=[1,2,3,3,4]
>>> x_set=set(x)
>>> print(x_set)
{1, 2, 3, 4}
If you want specific formatting, you will need to write that yourself.
Here is a subclass of set that implements that format:
class Myset(set):
def __str__(self):
return '{'+','.join(repr(e) for e in sorted(self))+'}'
print Myset([1,2,3])
# {1,2,3}
Or, just use Python 3x:
>>> print(set([1,2,3]))
{1, 2, 3}
The order may be different, however, without the sorted that I used above...
("{{{}}}".format(",".join(map(str,l))))
{1,2,3}
Extend the class from list and override __repr__ method
class List(list):
def __repr__(self):
return "{%s}"%(",".join([str(each) for each in self]))
l = List()
l.append(1)
l.append(2)
print l
{1,2}