Iterateing over a list python program - python

I wanted know how to iterate over a list in my code. I want to get rid of every index value that is equal to 10 and, after completing the program I got an index out of range error. I wanted to know what that means and how could I refine my code so that I get rid of every value that is equal to ten and then return the new list without the 10 values.
Here is my code:
mylist = [10,10,10,10,10,10,9,9,9,9,9,0,0,0]
for i in range(len(mylist)):
if mylist[i] ==10:
mylist.pop(i)
print( mylist)

An index out of range error is when you are trying to iterate past the amount of items in a data structure. so say you have 3 items in a list if you try access a 4th it will give an index error.
The issue you are having is because you are mutating the list as you iterate over it.
Its generally not a good idea to edit the data you are currently looping over. A better way might be to use a list comprehension like this
mylist = [10,10,10,10,10,10,9,9,9,9,9,0,0,0]
mylist = [x for x in mylist if x != 10]
>>> mylist
[9, 9, 9, 9, 9, 0, 0, 0]

Try the following if your goal is just to eliminate the items with value of 10:
>>> mylist = [10,10,10,10,10,10,9,9,9,9,9,0,0,0]
>>> [x for x in mylist if x != 10]
[9, 9, 9, 9, 9, 0, 0, 0]

Why you are getting Index Out Of Range: At the start of your program,
len(mylist) = 14, but as you remove elements from the list, the length
of your list decreases, and you end up accessing index that do not
exist.
How to fix it: You can try accessing the elements in reverse order and
removing 10, as you encounter it.
a = [10,10,10,10,10,10,9,9,9,9,9,0,0,0]
for i, e in reversed(list(enumerate(a))):
if e == 10:
a.pop(i)
print a

Related

Python for loop in enumerate list goes for infinite

I have a list of numbers and I want to run a for-loop through it, but as I update the list, the for loop does not stop and runs infinite time, here is my code:
a = [0,1,2,3,4,5,6]
for index, item in enumerate(a):
if item>0:
a.insert(index,10)
What should I do to just update and insert into list "a" and just doing for loop for pre defined list before adding new items?
Is that what you are looking for? (it is not clear..)
The code replaces every positive value with 10
a = [0, 1, 2, 3, 4, 5, 6]
a1 = [10 if x > 0 else x for x in a]
print(a1)
output
[0, 10, 10, 10, 10, 10, 10]
You can iterate over a copy of this list:
for index, item in enumerate(a.copy()):

How to create a new list everytime you loop and repeat the loop after appending elements to it?

This is my list
lst = [1,2,3,4,4,5,6,7,8,8,9,9,10,1]
I want this output
[1][2,3][4,4,5][6,7][8,8,9][9][10,1]
If the number is even and the next number is odd loop should break, and the next odd or even number should be appended in another list.
if there is even number, the list shouldn't be broken until the next odd is found.
lis = [1,2,3,4,4,5,6,7,8,8,9,9,10,1]
tempList = []
result = []
for item in lis:
tempList.append(item)
if item % 2 == 1:
result.append(tempList)
tempList = []
print(result)
It is hard to formulate a solution using break here.
May I suggest that you rewrite your psuedo-algorithm a little more concisely first. Something like:
For every item in the input list, append it to an output list.
If the item is odd then remember the current output list, and start
a new one.
Then, implemented in Python it looks like:
input_list = [1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 1]
output_list = [[]]
for x in input_list:
output_list[-1].append(x)
if x % 2 != 0:
output_list.append([])

removing elements in list(Python)

I have tried execute this, but it dosn't work properly. My goal was to remove all numbers divided by 2. Could someone advise what is wrong. I really do not understand why '4', '8' are still there.
list = [2,4,9,0,4,6,8,3,43,44]
for e in list:
if e%2==0:
list.remove(e)
print(list)
You can use a list comprehension to generate a new list with only elements you want to keep.
newList = [x for x in oldList if not isEven(x)]
where the function isEven does something like:
def isEven(target):
return target % 2 == 0
By the way, your question is a duplicate of the following How to remove items from a list while iterating?
If you want to keep the list instead of creating a new one (the answer by Thomas Milox is a good one otherwise), you should iterate backward through the list by index. When you remove an element from a list while iterating forwards through the list you may jump over some elements, not processing them. Going backward ensures that no list element removals move any elements that you may still want to process.
Here is an example of how this may look for your code:
list = [2, 4, 9, 0, 4, 6, 8, 3, 43, 44]
for i in range(len(list) - 1, -1, -1): # start at the last element, go until the first one (index 0 - the last value in the range method will not be reached), go backwards
if list[i] % 2 == 0:
del list[i]
You can read a bit more about removing an element by index instead of by value here.
This is required since you would otherwise mutate the list on the wrong position for duplicate values. It may also be a bit faster, since removeneeds to iterate through the list, searching for the element to remove while del list[i] may look up the element that needs to be removed by index.
Iterating backward through a list is also covered here.
You can try to use list.pop() with the position of the element you want to remove.
The '2' and '4' are still there because they are skipped when you remove the number before them (When you remove the '2', the '4' is moved to the previous position)
Try this:
l = [2, 3, 4, 5, 9, 10,30,45]
new=[el for el in l if el % 2]
print(new)
Actually, when you remove an element from the list, the indexing gets changed. So, you can do this list comprehension.
Also you can use:
l = [2, 3, 4, 5, 9, 10,30,45]
new=[filter(lambda x: x % 2, l)]
print(new)

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

Trying to understand insertion sort algorithm

I'm reading some books on Python, data structures, and analysis and design of algorithms. I want to really understand the in's and out's of coding, and become an efficient programmer. It's difficult to ask the book to clarify, hence my question on stackoverflow. I'm really finding Algorithms and recursion challenging ... I posted some code (insertion sort) below that I'm trying to understand exactly what's happening. I understand, generally, what is supposed to happen, but I'm not really getting the how and why.
From trying to analyze pieces of the code on Python Idle, I know that:
key (holds variables) = 8, 2, 4, 9, 3, 6
and that:
i (holds the length) = 7 ( 1, 2, 3, 4, 5, 6, 7)
I don't know why 1 is used in the first line: range(1, len(mylist)). Any help is appreciated.
mylist = [8, 2, 4, 9, 3, 6]
for j in range(1,len(mylist)):
key = mylist[j]
i = j
while i > 0 and mylist[i-1] > key:
mylist[i] = mylist[i - 1]
i -= 1
mylist[i] = key
Let me try to break this down.
Start by considering a list. It is "almost" sorted. That is, the first few elements are sorted, but the last element is not sorted. So it looks something like this:
[10, 20, 30, 50, 15]
Obviously, the 15 is in the wrong place. So how do we move it?
key = mylist[4]
mylist[4] = mylist[3]
mylist[3] = key
That'll switch around the 15 and the 50 so now the list looks like:
[10, 20, 30, 15, 50]
But we'd like to do this several times in a loop. To do that we can do:
while ???:
key = mylist[i]
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
That loop will go back one position at a time swapping the two elements. That'll move the out of order position one place back each time. But how do we know when to stop?
Let's look again at our list and the moves we want to make:
[10, 20, 30, 50, 15]
[10, 20, 30, 15, 50]
[10, 20, 15, 30, 50]
[10, 15, 20, 30, 50]
# stop! we are sorted now!
But what is different that last time around? Every time we move the number one place back, it is because the 15 is less then the element on the left, meaning its not sorted. When that is no longer true we should stop moving. But we can easily deal with that:
key = mylist[i]
while key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
Ok, but happens if we now try to sort this list:
[10, 20, 1]
[10, 1, 20]
[1, 10, 20]
# ERROR!!
At this point something bad happens. We try to check whether key < mylist[i-1] but when we've reached the beginning, i = 0, and this checks the end of the list. But we should stop moving to left at this point...
If we reach the beginning of the list, we can't move our pivot/key further so we should stop. We update our while loop to handle that:
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
So now we have a technique for sorting an almost sorted list. But how can we use that to sort a whole list? We sort parts of the list at a time.
[8, 2, 4, 9, 3, 6]
First we sort the first 1 elements:
[8, 2, 4, 9, 3, 6]
Then we sort the first 2 elements:
[2, 8, 4, 9, 3, 6]
Then we sort the first 3 elements
[2, 4, 8, 9, 3, 6]
So on and so forth
[2, 4, 8, 9, 3, 6]
[2, 4, 8, 9, 3, 6]
[2, 3, 4, 8, 9, 6]
[2, 3, 4, 6, 8, 9]
But how do we do we do that? With a for loop
for j in range(len(mylist)):
i = j
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
But we can skip the first time through, because a list of one element is obviously already sorted.
for j in range(1, len(mylist)):
i = j
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
A few minor changes which make no difference brings us back to your original code
for j in range(1, len(mylist)):
key = mylist[j]
i = j
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
i -= 1
mylist[i] = key
The insertion sort algorithm works by trying to build up a sorted list of increasing length at the start of the array. The idea is that if you start off by building a one-element sorted list at the beginning, then a two-element list, then a three-element list, etc., that once you've built up an n-element sorted list, you have sorted the entire array and are done.
For example, given the array
3 1 4
We can split this into a zero-element sorted list and a three-element unsorted list:
| 3 1 4
Now, we add 3 to our sorted list. Since that list is now only one element long, it's automatically sorted:
3 | 1 4
Now, we want to add 1 to our sorted list. If we just add 1 to the end of the list like this:
3 1 | 4
then the sorted list is no longer sorted. To fix this, the inner loop of the insertion sort code works by continuously swapping the 1 with the element before it until it's in the proper position. In our case, we swap the 1 and the 3:
1 3 | 4
and since the 1 is now at the beginning of the array, we don't need to move it any more. This is why the inner loop runs while i > 0; once the index of the new element (i) is at the start of the array, there's nothing before it that could be any bigger.
Finally, we update the array by adding 4 to the sorted list. Since it's in sorted position, we're done:
1 3 4
And our array is now in sorted order.
Now, to your original question: why does the outer loop start at 1? This is a cute optimization trick. The idea is that any one-element array must automatically be sorted. This means that the algorithm can start off by saying that the first element of the array is a one-element sorted list. For example, given the array
2 7 1 8
The insertion sort algorithm could try splitting this array like this, putting an empty sorted list at the front:
| 2 7 1 8
But a marginally faster option is to split the list like this:
2 | 7 1 8
which is guaranteed to be safe because any one-element list is automatically sorted.
This is really an optimization of the algorithm on the part of the authors. The algorithm would work perfectly fine if the outer loop started at zero, but they've just decided to start it at one to avoid an unnecessary loop iteration.
Hope this helps!
Have a look at the while loop. It starts with i having the value of 1, but then i is decreased. So in the last line, the minimum value of i could be 0, which is the first element in the list. If you would start with 0, i would become -1 which is valid in python, but means the last element. Therefore the range has to start with 1.
I would like to mention, that you are asking for insertion sort. I don't thin that your code implements insertion sort. Looks rather like bubble sort or something like that.
The reason is that:
i = j
and that mylist is accessed like:
mylist[i - 1]
Therefor the first value is 0. If the range would have started at 0, it would cause an mylist to be accessed at position -1.
Check out animated InsertionSort HERE
Later on i = j is set, and and myList[i-1] is accessed. So, j must be j >= 1.
Added: setting j = 0 is logicaly wrong because in the loop myList[j-1] is accessed - this is just by doing statical analysis of the code (and knowing i = j). Even if this cannot happen during runtime because of while i > 0, it is at least meaningless. If the expression myList[j-1] appears in the code, then it must surely be j >= 1.
The j-the iteration inserts the j-th element into the sorted elements before j. So it makes no sense to start with j=0. In the case j=1 the sublist below is myList[0:1] which is allways sorted, and the loop inserts myList[1] into the sublist myList[0:2]

Categories