Python: IndexError: list index out of range - python-2.7

I keep getting this error:
line 4, in timesTwo
IndexError: list index out of range
for this program:
def timesTwo(myList):
counter = 0
while (counter <= len(myList)):
if myList[counter] > 0:
myList[counter] = myList[counter]*2
counter = counter + 1
elif (myList[counter] < 0):
myList[counter] = myList[counter]*2
counter = counter + 1
else:
myList[counter] = "zero"
return myList
I'm not exactly sure how to fix the error. Any ideas?

You are setting the upper-bound of the while loop to the length of myList, which means that the final value of counter will be the length. Since lists are indexed starting at 0, this will cause an error. You can fix it by removing the = sign:
while (counter < len(myList)):
Alternatively, you could do this in a for loop that may be a bit easier to handle (not sure if this fits your use case, so the above should work if not):
def timesTwo(myList):
for index, value in enumerate(myList):
if value is not 0:
myList[index] *= 2
else:
myList[index] = 'zero'
return myList

Related

List manipulation to extract values greater than current and remaining index values

I have following list:
elev = [0.0, 632.8, 629.9, 626.5, 623.7, 620.7, 620.7, 607.4, 603.2, 602.0, 606.6, 613.2, 608.4, 599.7, 583.6]
Ideally it should be in descending order but 602.0 is smaller than next 3 values (606.6,613.2,608.4) and I need a count of those values each time this issue arises. I am trying nested for loops to count those values with following:
l = len(et)
for i in xrange(1,l-1,1):
for j in xrange(1,l-1,1):
if (et[i] < et[j]):
print et[i]
But instead I get all values greater than 602.0. How do I restrict loop to only count those 3 values? Appreciate any suggestions.
I guess this will solve your problem:
l = len(et)
for i in xrange(1,l-1,1):
if et[i] < et[i+1]:
for j in xrange(i,l-1,1):
if (et[i] < et[j]):
print et[j]
It will print the values greater than your number, not all but only the ones which came after the number.
This is what I've got from my terminal:
>>> for i in xrange(1,l-1,1):
... if et[i] < et[i+1]:
... print "for",et[i]
... for j in xrange(i,l-1,1):
... if (et[i] < et[j]):
... print et[j]
...
for 602.0
606.6
613.2
608.4
for 606.6
613.2
608.4
l_elev = len(elev)
gt_cnt = 0
eq_cnt = 0
slp_idx = []
for i in xrange(1,l_elev-3,1):
# following will take care of greater than current value inversion
if elev[i+gt_cnt] < elev[i+1+gt_cnt]:
lnew = elev[i+gt_cnt:]
gt_inv = [y for y in lnew if y >= elev[i+gt_cnt]]
gt_cnt += 1
for x in xrange(i,i+len(gt_inv),1):
slp_idx.append(x)
# following will take care of adjacent equal values
if (elev[i+eq_cnt] - elev[i+eq_cnt+1]) == 0:
cnew = elev[i:]
eq_inv = [y for y in cnew if y == elev[i+eq_cnt]]
eq_cnt+=1
for y in xrange(i,i+len(eq_inv),1):
slp_idx.append(y)
# break loop to avoid out of index error
if i+gt_cnt > l_elev:
break

List index out of range (Python 2.7)

I feel like I am constantly having this problem when I am writing a program, what I want to do is iterate over every value in my nested list and say that if it's not a zero, make it one.
Here is the error I am getting:
Traceback (most recent call last):
File "C:\Users\ryry3\Desktop\Python Projects\Games\Pygame Experiment\Sprint2.py", line 65, in <module>
resetBoard()
File "C:\Users\ryry3\Desktop\Python Projects\Games\Pygame Experiment\Sprint2.py", line 49, in resetBoard
if board[i][j] != 0:
IndexError: list index out of range
Here is my full code:
import random
grid = [100,100]
board = [[0,0,0,0,0,0,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,5,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]]
playerX = None
playerY = None
randX = 0
randY = 0
def getRandomGridPos():
global randX, randY
randX = int(random.uniform(0, grid[0]))
randY = int(random.uniform(0, grid[1]))
def main():
pass
def printBoard():
print str(board[0]).replace(',', '')
print str(board[1]).replace(',', '')
print str(board[2]).replace(',', '')
print str(board[3]).replace(',', '')
print str(board[4]).replace(',', '')
print str(board[5]).replace(',', '')
print str(board[6]).replace(',', '')
print str(board[7]).replace(',', '')
print str(board[8]).replace(',', '')
print str(board[9]).replace(',', '')
def resetBoard():
i = 0
j = 0
while i < 10:
if board[i][j] != 0:
board[i][j] = 0
j += 1
print "Looping"
if j == 10:
j = 0
i += 1
print "J == 10"
if i == 10:
j = 0
i = 0
print "I == 10"
else:
j += 1
resetBoard()
Can someone help me find a solution and also help me not get this error anymore (explain why it happens)?
You've already gotten several pointers to the cause of your error, but I just wanted to point out a clearer pattern to iterate multi-dimensional arrays:
for x in range(0, 10):
for y in range(0, 10):
# you will now have all values for a 10x10 array in x & y
if board[x][y] != 0:
board[x][y] = 0
If you really just want to make sure all board fields (10 x 10) are zeros, the following is even more consice:
# zero out a 10 x 10 multi-dimensional array
board = [[0] * 10] * 10
Your for reset board doesn't work for the following reasons:
"if i == 10" ,i never actually reaches 10, since it is in a while loop which states "while i < 10". The loop would exit before i actually reaches 10
no nested while loop. You need two while loops to reset the board.
When j reaches 10 this line raises an index error: if board[i][j] != 0: , because j equals 10, and the maximum index you can take of a 10 element list is 9(since index starts at 0)
I recommend reading the following
http://introtopython.org/lists_tuples.html
I would add that one of the best ways to achieve what you want in python with loops is:
for row in board: # runs the following once for every item in board
for item in row: # runs the following for every item in row.
# A second for statement is required because
# multidimensional lists are lists of lists.
if(item != 0)
item = 0 #sets items to 0 if the item isn't equal to 0
UPDATE:
Sorry but I also encoutered another problem, my bad for not checking the code:
The final code should be:
while i < 10:
if j == 10:
j = 0
i += 1
print ("J == 10")
elif board[i][j] != 0:
board[i][j] = 0
j += 1
print ("Looping")
else:
j += 1
The problem I missed was that you should have checked the j boundary before trying to access the array, only then you should start the loop again.
The problem is in this part:
if j == 10:
j = 0
i += 1
print "J == 10"
if i == 10:
j = 0
i = 0
if i = 9, j= 10 then we enter into the first if which changes i,j to be 10,10
Then the code continues and we enter the second if, thus reseting i and j making the loop go again and again...
Solve it by deleting the second if part, since the while condition will make sure we will never go to that case in the first place.

How to simplify for loop in prime number generator in python

import math
def is_prime(num):
if num < 2:
return False
for i in range(2, int(math.sqrt(num))+ 1):
if num % i == 0:
return False
return True
Primes seems to be a popular topic but in the book in which I am learning Python, I am on chpt 6 out of 21 and in the iteration chapter which it teaches while loops. I have not learned for loops yet although I understand what they do. So, let's say I have not learned for loops yet and am given only if/elif/else statements and the while loops as my tools. How can I change the for line of code into something more simple using the above tools? While asking this question I quickly came up with this code:
def formula(num):
i = 2
while i >= 2:
return int(math.sqrt(num)+ 1)
def is_primetwo(num):
i = 2
if num < 2:
return False
formula(num)
if num % i == 0:
return False
return True
It works but would this be a simple version of the for loop or is there something even more simple where I do not have to wrap a function within a function?
Absolutely, you do not need a function to replace a for loop.
So you've got this
for i in range(2, int(math.sqrt(num))+ 1):
which is your for loop. Take a second to think what it's doing.
1.) It's taking the variable i, and it's starting it at a value of 2.
2.) It's checking whether to do the loop every time by checking if i is less than the (square root of num) plus 1
3.) Every time through the loop, it adds one to i.
We can do all of these things using a while loop.
Here's the original
for i in range(2, int(math.sqrt(num))+ 1):
if num % i == 0:
return False
let's rename the second and third lines loop contents just so we're focusing on the looping part, not what logic we're doing with the variables i and num.
for i in range(2, int(math.sqrt(num))+ 1):
loop contents
ok, now let's just rearrange it to be a while loop. We need to set i to 2 first.
i = 2
Now we want to check that i is in the range we want
i = 2
while i <= int(math.sqrt(num) + 1):
loop contents
Now we're almost set, we just need to make i actually change, instead of staying at a value of 2 forever.
i = 2
while i <= int(math.sqrt(num) + 1):
loop contents
i = i + 1
Your example seemed to do some of these elements, but this way is a simple way to do it, and no extra function is necessary. It could be the range() function that is confusing. Just remember, the for loop is doing three things; setting a variable to an initial value, checking a condition (one variable is less than another), and incrementing your variable to be one large than previously to run the loop again.
How about something like:
from math import sqrt
def is_prime(num):
if (num < 2):
return False
i = 2
limit = int(sqrt(num) + 1)
while (i <= limit):
if num % i == 0:
return False
i = i + 1
return True
Not sure if this is what you want, but the for loop:
for i in range(2, int(math.sqrt(num))+ 1):
if num % i == 0:
return False
return True
can be expressed as:
i = 2
while i < int(math.sqrt(num))+ 1):
if num % i == 0:
return False
i += 1
return True
Probably a good idea to determine int(math.sqrt(num))+ 1) once:
i = 2
n = int(math.sqrt(num))+ 1)
while i < n:
if num % i == 0:
return False
i += 1
return True

How to print only last line in a while loop

count = 0
while count ** 2 < snum_:
print "Using search with increment 1, the root lies between", count,"and", count + 1
count = count + 1
How do I get the loop to only print the last possible line?
You can try this:
count = 0
while count < 4:
print('hi')
count += 1
else:
# Replace below string with what you wish.
print('end')
+= means count + 1. else is reached after while finishes (will not print, if you break the loop instead of letting it finish normally).
With a for-loop and itertools.count():
import itertools
for count in itertools.count(1):
if count**2 >= snum_:
print "Using search with increment 1, the root lies between %d and %d" % count-1, count
break
But the general idea can also be applied to your while loop: When count**2 is no longer less than snum_, print and break.
You could save the string you want to print and print it after the loop:
count = 0
result = ''
while count ** 2 < snum_:
result = "Using search with increment 1, the root lies between %d and %d" % count, count + 1
count = count + 1
print result

A little confused about binary search

I implemented a binary search in Python:
def bisect(seq, goal, lo=0, hi=None):
if hi == None:
hi = len(seq)
while True:
middle = (lo+hi)//2
if seq[middle] == goal:
return middle
elif goal < seq[middle]: hi = middle
elif goal > seq[middle]: lo = middle+1
if lo >= hi:
return -1
It should return the index of the item that is first met. However, when I apply it on a list like this:
seq = [-81, -81, 1, 2, 9, 10, 63, 79]
bisect(seq, -81)
it doesn't return 0 but 1. How can I fix this?
For such a seemingly simple problem, nonetheless, getting the boundary conditions exactly right can be a challenge. So what I normally do in these cases is just use, or more usually, copy and adjust the code in the bisect module. The function you want is bisect_left, since you want the index of the leftmost value if there are more than one, or the index of the insertion point if there is no match.
Here is a copy of the bisect_left function from the Python 3.3 Std Lib:
def bisect_left(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.
The return value i is such that all e in a[:i] have e < x, and all e in
a[i:] have e >= x. So if x already appears in the list, a.insert(x) will
insert just before the leftmost x already there.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if a[mid] < x: lo = mid+1
else: hi = mid
return lo
if seq[middle] == goal: return middle bails out without considering whether the same value might occur at a lower index. In your example, lo stays 0, hi becomes 7, then 3. When hi is 3, middle is 1, and that meets your condition so 1 is returned. Since any multiple occurrences of goal have to be consecutive to meet the condition that seq is nondecreasing (required for binary search), the easiest thing to do might be:
if seq[middle] == goal:
while middle > lo and seq[middle - 1] == goal:
middle = middle - 1
return middle