Nested list sorting in Python - python

This is a question of nested loop where I have to find the names of students in alphabetical order with 2nd lowest marks.
I am getting following error:
Traceback (most recent call last):
File "solution.py", line 12, in <module>
if (l[i][0]==l[0][0]):
IndexError: list index out of range
Following is my complete code.
l=list()
p=list()
q=list()
for i in range (int(raw_input())):
p=[raw_input(),int(raw_input())]
p.reverse()
l.append(p)
l.sort()
print len(l)
for i in range(0,len(l)):
print "i= ",i
if (l[i][0]==l[0][0]):
l.remove(l[i])
print l
for i in range(0,len(l)):
if (l[i][0]==l[0][0]):
q.append(l[i][1])
q.sort()
for i in range(0,len(q)):
print q[i]
I have even printed the index which shows the values are in range. Please run the function to find the following output:
4
i= 0
i= 1
i= 2
i= 3
I will happy if I get any better method from my the community ,But my main concern is the error I am getting "Index Out of Range" .It doesn't seem right here

The problem is that you are removing items from a loop. The thumb rule is that you shall never remove items from a list while iterating over it.
I don't really understand your code right now, but you can just change the way you are doing the first loop and apply the same logic for the next ones, at least you will have what you want.
The idea here is that with the while statement, after each iteration, you will have another verification of the size of the list. Meanwhile with the for loop, only at the first time, since range will return a list and the for loop will just iterate over the list which was already created.
l=list()
p=list()
q=list()
for i in range (int(raw_input())):
p=[raw_input(),int(raw_input())]
p.reverse()
l.append(p)
l.sort()
print len(l)
i = 0
while i < len(l):
print "i= ",i
if (l[i][0]==l[0][0]):
l.remove(l[i])
i += 1
print l

You are using remove, because of that l, in some moment, have less elements than you expect.

Related

IndexError: list index out of range with a while loop [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 2 years ago.
I've been trying to fix this but the same error message came up every time:
while number_list[i] <= number_list[j]:
IndexError: list index out of range
I've searched for the same type of bug, but not very similar cases found.
Here it is the head program (orders the numbers of my list, from the little one to the bigger):
number_list=[]
list_lenght=int(input("List lenght: "))
while len(number_list)<list_lenght:
item=input("Enter new item to the list:")
number_list.append(item)
print(number_list)
print("That's your number list: ",number_list)
number_list_final=[]
def order_number_list(number_list):
i=0
j=1
while (j)<=(len(number_list)-1):
while number_list[i]<=number_list[j]:
j=j+1
i=j
j=i+1
final_item=number_list[i]
number_list_final.append(final_item)`
del number_list[i]
order_number_list(number_list)
order_number_list(number_list)
print(number_list_final)
I know this is about iterating with the list while modifying it, but no idea how to fix it.
Can anyone help me to debug this, or give me some tips?
Thank you!
number_list=[]
list_lenght=int(input("List length: "))
while len(number_list)<list_lenght:
item=input("Enter new item to the list:")
number_list.append(int(item))
print(number_list)
print("That's your number list: ",number_list)
number_list_final=[]
def order_number_list(number_list):
current_low = ["number"]
current_low[0] = number_list[0]
x = 1
current_low_pos = 0
while x < len(number_list):
if current_low[0] > number_list[x]:
current_low[0] = number_list[x]
current_low_pos = x
x = x + 1
del number_list[current_low_pos]
if number_list == []:
remaining_list = []
else:
remaining_list = order_number_list(number_list)
return (current_low + remaining_list)
number_list_final = order_number_list(number_list)
print(number_list_final)
This is code that has been clarified and corrected.
j was not working right, as other answers have pointed out.
number_list.append(item)
needed to be changed to:
number_list.append(int(item))
because you cant compare strings with the '<' operator.
I also added a return statement, added this line of code:
number_list_final = order_number_list(number_list)
because your final print statement would print an empty list because:
order_number_list(number_list)
doesn't change the variable number_list_final.
I changed some of the function code to simply and make it more readable.
It also explicitly sets the current lowest item to be the first, and changes that if a lower item is found later on.
Hope this helps, let me know if you have any questions!
If I understand you correctly, you're trying to sort a list of numbers. There's a built-in Python method for this, that has been optimized for ages to be fast and use minimal memory, it's called sorted.
Instead of running order_number_list, try:
print(sorted(number_list))
If this is some kind of homework, and you're not allowed to use the built-in sorted, for educational purposes I would recommend you to use a sorting algorithm called bubble sort, more information here - Bubble Sort Homework.
Updating your code to include a couple of print statements shows that the j increases to past the length of the list. Then the "while number_list[i]<=number_list[j]:" no longer can be completed as there is no "number_list[j]" for the j value.
number_list=[1,2,3,4,5]
list_lenght=5
#=int(input("List lenght: "))
#while len(number_list)<list_lenght:
# item=input("Enter new item to the list:")
# number_list.append(item)
# print(number_list)
print("That's your number list: ",number_list)
number_list_final=[]
def order_number_list(number_list):
i=0
j=1
while (j)<=(len(number_list)):
while number_list[i]<=number_list[j]:
print (j)
print (i)
j=j+1
i=j
j=i+1
final_item=number_list[i]
number_list_final.append(final_item)
del number_list[i]
order_number_list(number_list)
order_number_list(number_list)
print(number_list_final)
This outputs :
That's your number list: [1, 2, 3, 4, 5]
1
0
2
0
3
0
4
0
Traceback (most recent call last):
File "C:/Python3/numberlist.py", line 30, in <module>
order_number_list(number_list)
File "C:/Python3/numberlist.py", line 19, in order_number_list
while number_list[i]<=number_list[j]:
IndexError: list index out of range
The code is falling over once j is 5 for this example, it is trying to compare to a number that doesnt exist

Indexing error scanning list

I apologize ahead of time for the basic nature of this question but I could really use a different set of eyes to see why I'm still getting an IndexError: list index out of range.
Here is my code:
def longestRun(L):
counter=1
ii=0
counts=[1]
while ii<=max(range((len(L)))):
if L[ii] <= L[(ii+1)]:
counter+=1
ii+=1
else:
ii+=1
counts.append(counter)
counter=1
continue
counts.sort()
return counts[-1]
It is supposed to count the longest streak of consecutive increases for a list of integers. I got it working by subtracting 1 from the while statement but then it will not always show the right answer because it won't go through the whole list.
Here is my specific error message:
IndexError
Traceback (most recent call last)
<ipython-input-76-1b4664f2fb31> in <module>()
----> 1 longestRun(L)
C:\Users\james_000\Desktop\longestRun.py in longestRun(L)
4 counts=[1]
5 while ii<=max(range((len(L)))):
----> 6 if L[ii] <= L[(ii+1)]:
7 counter+=1
8 ii+=1
Your while loop is while ii<=max(range((len(L)))): and then your if statement's condition accesses L[ii+1] which runs off the end of the array.
It's simple math. Let's say L is of length 10. That makes the last index 9. ii can eventually be 9, thus ii+1 is going to be out of range.

Why is there no list index out of range error in my Python program?

I'm new to Python and have been learning only for a week so please pardon me if the answer seems really obvious to those of you who are experienced. I have written a simple program as follows and don't understand why I don't get "error: list index out of range".
def sum13(nums):
sum=0
for i in range(1,len(nums)):
if nums[i]==13 or nums[i-1]==13:
sum=sum
else:
sum=sum+nums[i]
if len(nums)>=1:
if nums[0]==13:
sum=sum
else:
sum=sum+nums[0]
return sum
print(sum13([]))
When using the for loop in the function sum13(nums), I indicated range(1,len(nums)), and index 1 doesn't exist in an empty list. Why is there no error: list index out of range when I use the function sum13(nums) on an empty list?
Because
>>> len([])
0
and
>>> range(1, 0)
[]
(or an empty range object in python3)
so the loop doesn't perform any iteration and the access on nums[i] is never executed.

Iterative deletion from list (Python 2)

I've just started programming, and I'm solving Project Euler problems with Python for practice.
(This is problem #2, finding the sum of the even fibonacci numbers within 4 million.)
My problem appears in the loop at the bottom, where I'm trying to locate the odd numbers in the list, and delete them.
del fiblist[i] gives me the following error message:
Traceback (most recent call last):
File ".../euler.py", line 35, in
del fiblist[i]
IndexError: list assignment index out of range
I don't see what I'm doing wrong here, and would really appreciate if anyone could help me see what I'm doing wrong here.
#euler2
def fibonacciList(limit):
'''generates a list of fib numbers up to N'''
mylist = []
a,b = 1,2
while True:
if a <= limit:
mylist.append(a)
a,b = b,a+b
else:
break
return mylist
fiblist = fibonacciList(4000000)
for i in fiblist:
if i%2 != 0: #if not even, delete from list
print i
del fiblist[i]
print fiblist
One problem here is that i is the item from the list, not it's index. So when you do del fiblist[i] you are not removing i, but the value that is at index i (which doesn't exist so you get an error). This can be fixed by using enumerate() to get indices to use, however, doing so introduces a new problem.
The main issue here is that you can't modify the length of a list while you iterate over it, as it messes with Python's iteration. One solution would be to copy the list and work on a copy, but the better one is to use a list comprehension to do what you want:
[i for i in fiblist if i%2 == 0]
This produces a new list with only the elements you want in. List comprehensions are a powerful tool, so I suggest you watch the video I linked for more.

python : list index out of range error while iteratively popping elements

I have written a simple python program
l=[1,2,3,0,0,1]
for i in range(0,len(l)):
if l[i]==0:
l.pop(i)
This gives me error 'list index out of range' on line if l[i]==0:
After debugging I could figure out that i is getting incremented and list is getting reduced.
However, I have loop termination condition i < len(l). Then why I am getting such error?
You are reducing the length of your list l as you iterate over it, so as you approach the end of your indices in the range statement, some of those indices are no longer valid.
It looks like what you want to do is:
l = [x for x in l if x != 0]
which will return a copy of l without any of the elements that were zero (that operation is called a list comprehension, by the way). You could even shorten that last part to just if x, since non-zero numbers evaluate to True.
There is no such thing as a loop termination condition of i < len(l), in the way you've written the code, because len(l) is precalculated before the loop, not re-evaluated on each iteration. You could write it in such a way, however:
i = 0
while i < len(l):
if l[i] == 0:
l.pop(i)
else:
i += 1
The expression len(l) is evaluated only one time, at the moment the range() builtin is evaluated. The range object constructed at that time does not change; it can't possibly know anything about the object l.
P.S. l is a lousy name for a value! It looks like the numeral 1, or the capital letter I.
You're changing the size of the list while iterating over it, which is probably not what you want and is the cause of your error.
Edit: As others have answered and commented, list comprehensions are better as a first choice and especially so in response to this question. I offered this as an alternative for that reason, and while not the best answer, it still solves the problem.
So on that note, you could also use filter, which allows you to call a function to evaluate the items in the list you don't want.
Example:
>>> l = [1,2,3,0,0,1]
>>> filter(lambda x: x > 0, l)
[1, 2, 3]
Live and learn. Simple is better, except when you need things to be complex.
What Mark Rushakoff said is true, but if you iterate in the opposite direction, it is possible to remove elements from the list in the for-loop as well. E.g.,
x = [1,2,3,0,0,1]
for i in range(len(x)-1, -1, -1):
if x[i] == 0:
x.pop(i)
It's like a tall building that falls from top to bottom: even if it is in the middle of collapse, you still can "enter" into it and visit yet-to-be-collapsed floors.
I think the best way to solve this problem is:
l = [1, 2, 3, 0, 0, 1]
while 0 in l:
l.remove(0)
Instead of iterating over list I remove 0 until there aren't any 0 in list
List comprehension will lead you to a solution.
But the right way to copy a object in python is using python module copy - Shallow and deep copy operations.
l=[1,2,3,0,0,1]
for i in range(0,len(l)):
if l[i]==0:
l.pop(i)
If instead of this,
import copy
l=[1,2,3,0,0,1]
duplicate_l = copy.copy(l)
for i in range(0,len(l)):
if l[i]==0:
m.remove(i)
l = m
Then, your own code would have worked.
But for optimization, list comprehension is a good solution.
The problem was that you attempted to modify the list you were referencing within the loop that used the list len(). When you remove the item from the list, then the new len() is calculated on the next loop.
For example, after the first run, when you removed (i) using l.pop(i), that happened successfully but on the next loop the length of the list has changed so all index numbers have been shifted. To a certain point the loop attempts to run over a shorted list throwing the error.
Doing this outside the loop works, however it would be better to build and new list by first declaring and empty list before the loop, and later within the loop append everything you want to keep to the new list.
For those of you who may have come to the same problem.
I am using python 3.3.5. The above solution of using while loop did not work for me. Even if i put print (i) after len(l) it gave me an error. I ran the same code in command line (shell)[ window that pops up when we run a function] it runs without error. What i did was calculated len(l) outside the function in main program and passed the length as a parameter. It worked. Python is weird sometimes.
I think most solutions talk here about List Comprehension, but if you'd like to perform in place deletion and keep the space complexity to O(1); The solution is:
i = 0
for j in range(len(arr)):
if (arr[j] != 0):
arr[i] = arr[j]
i +=1
arr = arr[:i]
x=[]
x = [int(i) for i in input().split()]
i = 0
while i < len(x):
print(x[i])
if(x[i]%5)==0:
del x[i]
else:
i += 1
print(*x)
Code:
while True:
n += 1
try:
DATA[n]['message']['text']
except:
key = DATA[n-1]['message']['text']
break
Console :
Traceback (most recent call last):
File "botnet.py", line 82, in <module>
key =DATA[n-1]['message']['text']
IndexError: list index out of range
I recently had a similar problem and I found that I need to decrease the list index by one.
So instead of:
if l[i]==0:
You can try:
if l[i-1]==0:
Because the list indices start at 0 and your range will go just one above that.

Categories