.remove() in Python list breaks a for loop [duplicate] - python

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 6 years ago.
I wrote a for loop that supposedly removes any elements that fits the description.
Example:
for tag in tags:
if tag.lower() in ['ex1', 'ex2', 'ex3']:
tags.remove(tag)
My tags would look like ['EX1', 'EX2', 'ex1', 'ex2', 'ex3', 'ex4', 'ex5'] and I expect to keep only ex4 and ex5
What I noticed is that the for loop would skip some elements, giving me results like ['EX2', 'ex2', 'ex4', 'ex5']
I suspect this being indexing issue, but I'm not sure if that's really the case.
I ended up using a list comprehension, which does the job correctly, but I just want to understand the true reason behind the unexpected behavior.

Python has a hard time iterating through something that is being changed during the iteration. You can instead use a copy:
for tag in tags[:]:
if tag.lower() in ['ex1', 'ex2', 'ex3']:
tags.remove(tag)

Related

Why does list[0:len(list)+1:-1] return an empty list? [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 1 year ago.
First time using StackOverflow, apologies in-case of any issues.
In python,
list[::-1] returns the reversed list
list[0:len(list)+1] returns the complete list
So why list[0:len(list)+1:-1] returns an empty list?
Further, for a list l= [0,1,2,3,4,5], if I want like [4,3,2]:
Trying l[2:5:-1], returns an empty list. But l[2:5][::-1] works.
Can anyone explain why this is happening? Or what is python actually doing when we slice a list, with a value for step?
Thanks in advance :)
some_list[start:stop:step] means give me elements starting at start and incrementing by step until you hit stop.
Well, if you start at 0 and increment by -1, you never actually reach the stop.

How to remove "sub-lists" from a list? [duplicate]

This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 3 years ago.
I am having trouble creating a function since I want to be able to refer to the tuple and not the list which contains the tuples. Hence I have come to the conclusion that I want to get rid of the inner square brackets.
I have a list similar to this:
List=[[(1,2),(3,4),(5,6)],[(1,2),(5,7),(3,8)],[...],[...]]
So the question I am asking is how can I remove the inner [ ] so that I can just produce a single list of tuples.
Also, I am not sure if I am allowed to ask another question, but how would i also delete duplicates (x,y) entries in my new list?
I have not provided code for this since I know the problem for the code I have and I believe I would confuse people by including it. If however, you wish to see the code, or want me to clarify anything please let me know.
I think this has been asked and answered on here multiple times. The solution to the flattening problem would be as follows:
new_list = [tupl for l in List for tupl in l]

for loop, and url.remove() only affecting every other entry [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 4 years ago.
Getting some confusing behaviour when running a for loop and removing entries from a list (cleaning out invalid urls):
urls = ['http://a.com/?mail=a#b.com','mailto:a#a.com', 'mailto:a#b.com', 'mailto:a#c.com', 'mailto:a#d.com']
for s in urls:
if '#' in s and '?' not in s:
urls.remove(s)
print(urls)
The output is:
['mailto:a#b.com', 'mailto:a#d.com']
It is consistently every other entry, so I'm assuming my understanding of python is not correct.
I looked into list comprehension with Python and ended up with:
urls = [s for s in urls if not ('?' not in s and '#' in s)]
This does what I want it to.
Is that the best way, can someone explain the behaviour, because I don't get it.
Thanks
The problem with your first solution is that you iterate over an object while deleting entries from it. The topic is discussed here for example: How to remove items from a list while iterating?
If you are trying to remove from list while iterating over, take a copy and iterate. urls[:] takes a copy of urls and you iterate over that. This prevents some unexpected situations that occur when iterating through the original list:
urls = ['http://a.com/?mail=a#b.com','mailto:a#a.com', 'mailto:a#b.com', 'mailto:a#c.com', 'mailto:a#d.com']
for s in urls[:]:
if '#' in s and '?' not in s:
urls.remove(s)
print(urls)
But, I would rather prefer the list-comprehension version of yours, that's more concise and pythonic.

loop a list - length of list but do not need the item created, pythonic? [duplicate]

This question already has answers here:
Is it possible to implement a Python for range loop without an iterator variable?
(15 answers)
Closed 4 years ago.
This is going to be a bit silly of a question. I have a simple list:
my_list = ["apple", "orange", "car"]
And I'd like to run a loop for the length of that list, but I don't need anything in the list. I can clearly do this:
for item in my_list:
call_external_thingy()
Which would loop 3 times, perfect. However, I'm never using the item in my for loop. So while this does work, everytime I look at my code I feel that I've made a mistake, "Oh shoot, I didn't pass item in.. oh right I just need to run that command for the number of items in the list..."
What would be the more pythonic way to simply run a for loop for the number of items in a list without creating item. I'm thinking of something with len or range but can't get my head around it and anything I mock up just looks like a big mess.
Note, I'm tempted to put this on codereview instead, but they usually want all the code and a lot of why. This seems like a simple enough question to be here, but I could be wrong!
Thank you!
This is pythonic :
for _ in my_list:
call_external_thingy()
for i in range(len(my_list)):
call_external_thingy()

for loop and a list.remove() doesn't remove all the items in the list in python [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 4 years ago.
names_friends=["Juan","Efren","Kiki", "Esmoris", "Diego", "Nando"]
for i in names_friends:
print(i)
names_friends.remove(i)
print(names_friends)
After run this code I got this.
Juan
Kiki
Diego
['Efren', 'Esmoris', 'Nando']
I would highly appreciate if someone could explain to me why it doesn't remove all the items of the list.Thanks
You are changing the iterable while iterating over it. So once you delete a object from it, it may skip the next one.
If you iterate over a copy, this problem goes away, e.g.
for i in names_friends[:]:
print(i)
names_friends.remove(i)

Categories

Resources