Editing a List From Inside a For Loop - python

Let's say I have a list, mylist, and I define it to be [1, 2, 3, 4, 5]. How is there a simple way to double every element of the list from within a for loop?
I know you could do something like:
for i in range(len(mylist)):
mylist[i] *= 2
I also know that you could make a list comprehension:
mylist = [2*i for i in range(1, 6)
But is there a way to do it like this?
for num in mylist:
#code goes here
I tried doing something like:
for num in mylist:
num *= 2
but num is a local variable, so this doesn't modify mylist, just num. Does anyone know a good way to do this?

The usual way to do this is with a list comprehension, iterating directly over the list items, not indirectly via an index.
mylist = [1, 2, 3, 4, 5]
mylist = [2 * num for num in mylist]
print(mylist)
output
[2, 4, 6, 8, 10]
That replaces mylist with a new list object. That's generally ok, but sometimes you want to modify the existing object, eg when other objects have a reference to mylist. You can do that with a slice assignment.
mylist[:] = [2 * num for num in mylist]

It's not really possible since you shouldn't try to change a list while looping through it in that way. I would stick with your other two ways of manipulating the list

Using an explicit for loop. Use enumerate while iterating and assign a new value to each item.
mylist = [1, 2, 3, 4, 5]
for i, n in enumerate(mylist):
mylist[i] = n * 2
Just be careful - don't change the number of items in a list: Remove items from a list while iterating

Related

Multiplying only odd indexes in a for loop

Multiplying only odd indexes with for loop
Why its not working?
myList = [1, 2, 3, 4, 5]
index = 0
for num in myList:
if index % 2 != 0:
num *= 2
index += 1
print(myList) # here the output still the same list
I want the output to be [1, 4, 3, 8, 5]
Edit: I see that you have edited your question, where you fixed the first issue of checking if the items in the list are odd or not. You are however still iterating over the list using for num in myList, which under the hood creates an Iterator which moves over your list. This means that whatever you do with num, you are only modifying num and not myList[index]. In order to modify the list directly, you will need to reference myList[index]. I strongly recommend you look into using enumerate, see my original answer for how to apply it to your use-case.
Your problem is that you are checking if the value inside myList is even or odd instead of its index.
Also, modifying num within the loop does not modify the value in your original list (this can easily be noticed since in the "modified" list the odd values are not multiplied).
Using the range(len()) idiom to loop over your list would yield the following code:
myList = [1, 2, 3, 4, 5]
for idx in range(len(myList)):
if idx % 2 != 0:
myList[idx] *= 2
print(myList)
You could further shorten the loop/assignment by using enumerate and list comprehension:
myList = [1, 2, 3, 4, 5]
myList = [num * 2 if idx % 2 != 0 else num for idx, num in enumerate(myList)]
print(myList)
Your way isn't working because you are not assigning 'num' back into the list.
newList = [v*2 if idx % 2 != 0 else v for idx, v in enumerate(myList)]
There are two issues in the code -
You need to check if the index is odd or even, and not the element.
Modifying num won't modify the corresponding element in the list as it does not reference the element in the list.
myList = [1, 2, 3, 4, 5]
for idx in range(len(myList)):
if idx % 2 != 0:
myList[idx]*=2

Is it safe practice to edit a list while looping through it?

I was trying to execute a for loop like:
a = [1,2,3,4,5,6,7]
for i in range(0, len(a), 1):
if a[i] == 4:
a.remove(a[i])
I end up having an index error since the length of the list becomes shorter but the iterator i does not become aware.
So, my question is, how can something like that be coded? Can the range of i be updated in each iterations of the loop based on current array condition?
For the .pop() that you mention for example you can use a list comprehension to create a second list or even modify the original one in place. Like so:
alist = [1, 2, 3, 4, 1, 2, 3, 5, 5, 4, 2]
alist = [x for x in alist if x != 4]
print(alist)
#[1, 2, 3, 1, 2, 3, 5, 5, 2]
As user2393256 more generally puts it, you can generalize and define a function my_filter() which will return a boolean based on some check you implement in it. And then you can do:
def my_filter(a_value):
return True if a_value != 4 else False
alist = [x for x in alist if my_filter(x)]
I would go with the function solution if the check was too complicated to type in the list comprehension, so mainly for readability. The example above is therefore not the best since the check is very simple but i just wanted to show you how it would be done.
If you want to delete elements from your list while iterating over it you should use list comprehension.
a = [1,2,3,4,5,6,7]
a = [x for x in a if not check(x)]
You would need to write a "check" function that returns wether or not you want to keep the element in the list.
I don't know where you are going with that but this would do what I beleive you want :
i=0
a = [1,2,3,4,5,6,7]
while boolean_should_i_stop_the_loop :
if i>=len(a) :
boolean_should_i_stop_the_loop = False
#here goes what you want to do in the for loop
print i;
a.append(4)
i += 1

Using for loop in Python 3.4 to remove particular element from array

As I am new to programming in Python. I am trying to remove particular elements from array using for loop which looks like
a=[2,3,1,4,1,1,1,5]
n=a.count(1)
for i in range (len(a)-n):
if (a[i]==1):
del a[i]
else:
a[i]=a[i]
print (a)
I want to remove 1 from array a. But, I am getting result as:
[2, 3, 4, 1, 1, 5].
That is 1 still exists in my new array. Can somebody please answer my problem?
try like this:
a = [2,3,1,4,1,1,1,5]
a = [x for x in a if x!=1] # this is called list comprehension
note Never modify list while iterating
Use a while loop and the remove method:
a = [2, 3, 1, 4, 1, 1, 1, 5]
while 1 in a:
a.remove(1)
print a
The real answer to your question (which none of the other answers addresses) is that every time you remove an item, the index i moves past it.
in your case:
a = [2,3,1,4,1,1,1,5]
after deleting the 5th item in the original list, the pointer moves to the 6th item, and the new 5th item (the second 1 in the sequence of three 1s) is skipped.
Regarding the comment never modify a list in a loop, try to implement an in-place algorithm like Fisher-Yates without modifying the list. Never say never. Know what you're doing.
The OP changes the list in-place, not creating a new list.
There are two methods, the second is safe, the first might be faster.
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(len(a)-1, -1, -1):
if a[i] == toremove:
del a[i]
and
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(a.count(toremove)):
a.remove(toremove)
The second removes the element however many times it exists (before the loop). Since we are not iterating on the list, it is safe to use the remove method.
Both fragments should be O(n) (but haven't done the calculations).
You can copy a and then remove but you cannot iterate over and delete elements from the same list, if your list starts with n elements python will have n pointers to each element so removing elements from the list as your are iterating over it will cause elements to be missed.python has no way of knowing you have removed elements from the list:
a = [2,3,1,4,1,1,1,5]
for ele in a[:]:
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
You can also use reversed which returns and iterator avoiding creating a whole copy of the list at once:
a = [2,3,1,4,1,1,1,5]
for ele in reversed(a):
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
Or using a list comprehension with the [:] syntax so we actually update the original object:
a[:] = (ele for ele in a if ele != 1)
All the above are linear operations using a single pass over a.
Actually as the del statement will remove elements from your list , and as the list that you bound in your loop doesn't been update after the first deleting you remove incorrect elements from your list , so if you want to use del you need to make the list name in your loop to reference to new list , that you can use a function for this aim , but as a more python way you can just use a list comprehension:
>>> a=[2,3,1,4,1,1,1,5]
>>> a=[i for i in a if i !=1]
>>> a
[2, 3, 4, 5]
Or you can use filter :
>>> a=[2,3,1,4,1,1,1,5]
>>> a=filter(lambda x: x !=1,a)
>>> a
[2, 3, 4, 5]

Concatenate List Object Name with a Number and Retain the List Python

I'm using python 2.7 I'm trying to figure out a way to change the names of my lists automatically.
Let me explain i have multiple lists
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 9, 3]
list3 = [8, 4, 3, 2, 1]
I would like to call the lists in a loop to determine which lists contain or do not contain a particular number.
My first thought was
x = "list" + str(i) # (where i iterates in the loop)
print x
However, using the above code only gave me the string "list1"(when i=1).
What I want is to be able to call the list that is named list1 and use the .count() operator to determine whether or not the number exists if it doesn't i want to call the next list until I'm out of lists(there will eventually be up to 30 lists).
Thanks,
Ryan
You shouldn't approach it like this. Put your lists in a container to iterate over them instead:
In [5]: for l in (list1, list2, list3):
...: print l.count(2)
...:
1
0
1
What you could do in a real-life use case is create a list of lists and fill it dynamically.
Then to get the first list that contains a given number, you could do:
In [6]: lists = [list1, list2, list3]
In [7]: next(l for l in lists if 9 in l)
Out[7]: [4, 5, 9, 3]
put the list in dict:
list1 = [1,2.4]
list2 = [2,5,6]
dlist = {1:list1,2:list2}
for k in dlist:
print dlist[k]

Why is list.remove only removing every second item? [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 7 months ago.
In my Python 2.7.2 IDLE interpreter:
>>> mylist = [1, 2, 3, 4, 5]
>>> for item in mylist:
mylist.remove(item)
>>> mylist
[2, 4]
Why?
It's because when you iterate over a list, python keeps track of the index in the list. Consider the following code instead:
for i in range(len(mylist)):
if i >= len(mylist):
break
item = mylist[i]
mylist.remove(item)
If we track this (which is essentially what python is doing in your code), then we see that when we remove an item in the list, the number to the right shifts one position to the left to fill the void left when we removed the item. The right item is now at index i and so it will never actually get seen in the iteration because the next thing that happens is we increment i for the next iteration of the for loop.
Now for something a little clever. If instead we iterate over the list backward, we'll clear out the list:
for item in reversed(mylist):
mylist.remove(item)
The reason here is that we're taking an item off the end of the list at each iteration of the for loop. Since we're always taking items off the end, nothing needs to shift (assuming uniqueness in the list -- If the list isn't unique, the result is the same, but the argument gets a bit more complicated).
Of course, If you're looking to remove all the items from a list, you can do that really easily:
del mylist[:]
or even with slice assignment:
mylist[:] = []
(I mention the latter because it can be useful to replace segments of a list with other items which don't even need to be the same length).
That's because you're modifying the list while iterating over it, iterate over a shallow copy instead:
>>> mylist = [1, 2, 3, 4, 5]
>>> for item in mylist[:]: #use mylist[:] or list(mylist)
mylist.remove(item)
...
>>> mylist
[]
You are modifying your list while you are looping through it, which is very bad practice.
Problem is that you are altering the list while iterating on it. Use a list comprehension instead:
mylist = [1, 2, 3, 4, 5]
mylist = [x for x in mylist if condition(x)]
>>> mylist = [1, 2, 3, 4, 5]
>>> for item in mylist:
mylist.remove(item)
in this loop :
1st time it will take 0th element (1) as an item and remove it from mylist.so after that mylist will be [2,3,4,5] but the pointer will be in the 1th element of the new mylist ([2,3,4,5]) that is 3. and it will remove 3.so 2 will not be remove from the list.
thats why after the full operation [2,4] will be left.
using for loop:-
>>>for i in range(len(mylist)):
mylist.remove(mylist[0])
i-=1
>>>mylist
[]
you can do this using while loop:
>>>mylist = [1, 2, 3, 4, 5]
>>>while (len(mylist)>0):
mylist.remove(mylist[0])
print mylist
Use a deep copy of mylist
mylist = [1, 2, 3, 4, 5]
l = [k for k in mylist] # deep copy
for i in range(len(mylist)):
mylist.remove(l[i])
print
print mylist

Categories