Posts: 300
Threads: 72
Joined: Apr 2019
Hi
This is very naïve, but i'm wondering if there's a more relevant way to remove an element from a list?
Thanks
myList = [5, 30, 100, 10]
val2Remove = 100
myList_to_str = [str(elem) for elem in myList]
str_val = str(val2Remove)
myList_to_str.remove(str_val)
myList = [int(elem) for elem in myList_to_str]
Posts: 2,128
Threads: 11
Joined: May 2017
- the names are not pythonic
- use the method remove to remove items from the list
- if an item is not in the list and you use the method
remove , then a ValueError is thrown. You can catch this exception.
my_list = [5, 30, 100, 10]
remove_val = 100
try:
my_list.remove(remove_val)
except ValueError:
print(remove_val, "not found")
else:
print(remove_val, "has been removed once.") But if 100 is more than once in the list, this code above removes only the first occurring 100.
Then it's easier to create a new list:
my_list = [100, 5, 30, 100, 10, 100]
remove_val = 100
new_list = [value for value in my_list if value != remove_val] This code does not throw an exception, if 100 is not in the list at all.
Posts: 1,094
Threads: 143
Joined: Jul 2017
Internally, Python lists are integer indexed dynamic arrays. Here is an interesting, if old, question and interesting answers and links on stackoverflow.
There is quite a lot going on behind the scenes when you add or delete elements!
As I understand it, you cannot access the values in a list without using the pointer variables, the index, which tells us where they are in memory and what kind of value is stored there.
So, if my_list.remove(3) seems to get rid of 3 without using its index, that is only superficially so.
I don't know how .remove() works internally, but you can fake it like this:
def remove_it(val, alist):
for i in range(len(alist)):
if alist[i] == val:
alist.pop(i)
return alist
my_list = [1, 2, 3, 4, 5]
remove_it(3, my_list) Output: [1, 2, 4, 5]
Or like this:
def remove_it(val, alist):
for i in range(len(alist)):
if alist[i] == val:
del alist[i]
return alist
my_list = [1, 2, 3, 4, 5]
remove_it(3, my_list) Output: [1, 2, 4, 5]
Posts: 2,128
Threads: 11
Joined: May 2017
Feb-21-2025, 09:25 AM
(This post was last modified: Feb-21-2025, 09:25 AM by DeaD_EyE.)
Your code example is wrong.
- Indentation of return
- the use of range(len(element)), iterate directly
- alist is modified in-place and is also returned
- Iterating over a list and modifying the list in-place will throw an
IndexError .
If you change then indentation to iterate over all elements, then you would get an IndexError .
This modifies the list in-place and does return None :
def remove_it(val, alist):
remove = []
for index, element in enumerate(alist):
if element == val:
remove.append(index)
for index in reversed(remove):
alist.pop(index)
my_list = [3, 1, 2, 3, 4, 5, 3]
print(my_list)
remove_it(3, my_list)
print(my_list)
Posts: 1,094
Threads: 143
Joined: Jul 2017
Entspann dich Alter, das hier ist nicht die Prüfung zum Pythonmeister des Jahres! War nur 'ne Vermutung darauf wie .remove(3) eventuell seine Wunder wirkt!
Quote:Indentation of return:
if return was not so indented, an IndexError would surface. As it is it works.
Quote:the use of range(len(element)), iterate directly:
not sure what you mean here; type(len(mylist)) returns: <class 'int'> I think it is OK to range(int).
Quote:alist is modified in-place and is also returned:
alist is passed to the function. LEGB means, the function looks first Locally and finds alist. In effect, it is a copy of alist.
Quote:Iterating over a list and modifying the list in-place will throw an IndexError.:
Not necessarily. Try the function remove_it(val, alist), let me know if you get an IndexError.
mylist.remove(3) only removes 1 instance of 3.
Quote:But if 100 is more than once in the list, this code above removes only the first occurring 100.
I'm sure it is possible to alter remove_it() to eliminate all instances of val. I wasn't aware that was the goal! That is not the way .remove() works.
Ist es nicht anstrengend, immer humorlos und streng zu sein? Lighten up a little ja?
Posts: 135
Threads: 0
Joined: Jun 2019
Iterating over a list and modifying it at the same time is never a good idea, as it can lead to obvious to weird errors. Or, to put it short: simply never do it. It's an absolute anti-pattern.
Regards, noisefloor
Posts: 1,094
Threads: 143
Joined: Jul 2017
Quote:Iterating over a list and modifying it at the same time is never a good idea, as it can lead to obvious to weird errors. Or, to put it short: simply never do it. It's an absolute anti-pattern.
Sure, if you wish to keep iterating. CPython ob_size is reallocated.
The problem arises, maybe not immediately, when you continue iterating to an index value that is no longer present in the list. But, if you leave the loop when you find what you want, you will never have this problem!
You don't need the function remove_it(val, alist) below, Python already has .remove(val). I was just wondering how .remove(val) works.
Rules can be helpful, but rules may also be, and often are, broken.
From the link I posted above:
Quote:The C code is pretty simple, actually. Expanding one macro and pruning some irrelevant comments, the basic structure is in listobject.h, which defines a list as:
typedef struct {
PyObject_HEAD
Py_ssize_t ob_size;
/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item;
/* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
* Invariants:
* 0 <= ob_size <= allocated
* len(list) == ob_size
* ob_item == NULL implies ob_size == allocated == 0
*/
Py_ssize_t allocated;
} PyListObject;
PyObject_HEAD contains a reference count and a type identifier. So, it's a vector/array that overallocates. The code for resizing such an array when it's full is in listobject.c. It doesn't actually double the array, but grows by allocating
You can see, behind the scenes, unseen by the Python user, there is a lot going on!
If you want to get rid of all instances of val in a list, the following, rule-breaking, code works without error. This is just for simulating what I think .remove(val) does.
def remove_it(val, alist):
for i in range(len(alist)):
if alist[i] == val:
del alist[i]
return alist
my_list = [3, 1, 2, 3, 4, 5, 3, 3]
while not remove_it(3, my_list) is None:
if type(remove_it(3, my_list)) == 'list':
my_list = remove_it(3, my_list) Output: my_list: [1, 2, 4, 5]
Posts: 2,128
Threads: 11
Joined: May 2017
(Feb-21-2025, 04:05 PM)Pedroski55 Wrote: Entspann dich Alter, das hier ist nicht die Prüfung zum Pythonmeister des Jahres! War nur 'ne Vermutung darauf wie .remove(3) eventuell seine Wunder wirkt!
Ich bin nicht dein "Alter"!
Du zeigst Anfängern den falschen Weg. Des Weiteren führen Vermutungen beim Programmieren immer zu unerwarteten Ergebnissen. Dein Beispiel kann als Negativ-Beispiel dienen, wie man es nicht machen solle. Ja, auch das sollte man lernen.
Quote:Note: Never change the object to be iterated during an iteration.
|