indexing error in list in python - python

B=l.append((l[i]+A+B))
l is a list here and i am trying to append into it more value for it to act as an array . But its still giving me error like list index out of range . How to get rid of it ?

There are many problems in your code:
1) the append method does not return anything, so it does not make sense to write B = l.append(...)
2) The double parenthesis are confusing, the code you wrote is exactly equivalent to B.append(l[i]+A+B)
3) Finally, obviously, the index i must be a valid index for the list l, otherwise you will get an IndexError exception.

List index out of range means that i is greater than len(l) - 1 (since Python, and many other programming languages, use indexing that starts at 0 instead of 1, the last item in the list has index len(l) - 1, not just len(l).
Try debugging like so:
try:
B = l.append((l[i] + A + B))
except IndexError:
print "Appending from index", i, "to list l of length:", len(l)
raise
This will tell you the value of i and the length of l when the append fails so you can search for the problem.
Is this in a loop? It may help to show us the code of the loop. It could be that, even though you're increasing the length of l by appending to it, you're increasing i even faster, so that it eventually gets to be bigger than len(l) - 1.

Variable i is larger or equal to the size of the l array.

Related

Built in (remove) function not working with function variable

Have a good day everyone, pardon my lack of understanding, but I can't seem to figure out why python built in function does not work when being called with another function variable and it just doesn't do what I want at all. Here is the code
def ignoreten(h):
ignoring = False
for i in range (1,len(h)-2):
if ignoring == True and h[i]==10:
h.remove(10)
if ignoring == False and h[i] ==10:
ignoring = True
The basic idea of this is just to decided the first 10 in a list, keep it, continue iterating until you faced another 10, then just remove that 10 to avoid replication, I had searched around but can't seem to find any solution and that's why I have to bring it up here. Thank you
The code you listed
def ignoreten(h):
ignoring = False
for i in range (1,len(h)-2):
if ignoring == True and h[i]==10:
h.remove(10)
if ignoring == False and h[i] ==10:
ignoring = True
Will actually do almost the exact opposite of what you want. It'll iterate over h (sort of, see [1]), and if it finds 10 twice, it'll remove the first occurrence from the list. (And, if it finds 10 three times, it'll remove the first two occurrences from the list.)
Note that list.remove will:
Remove the first item from the list whose value is equal to x. It
raises a ValueError if there is no such item.
Also note that you're mutating the list you're iterating over, so there's some additional weirdness here which may be confusing you, depending on your input.
From your follow-up comment to my question, it looks like you want to remove only the second occurrence of 10, not the first and not any subsequent occurrences.
Here are a few ways:
Iterate, store index, use del
def ignoreten(h):
index = None
found_first = False
for i,v in enumerate(h):
if v == 10:
if not found_first:
found_first = True
else:
index = i
break
if index is not None:
del h[index]
A little more verbose than necessary, but explicit, safe, and modifiable without much fear.
Alternatively, you could delete inside the loop but you want to make sure you immediately break:
def ignoreten(h):
found_first = False
for i,v in enumerate(h):
if v == 10:
if not found_first:
found_first = True
else:
del h[i]
break
Collect indices of 10s, remove second
def ignoreten(h):
indices = [i for (i,v) in enumerate(h) if v == 10]
if len(indices) > 1:
del h[indices[1]] # The second index of 10 is at indices[1]
Clean, but will unnecessarily iterate past the second 10 and collect as many indices of 10s are there are. Not likely a huge issue, but worth pointing out.
Collect indices of 10s, remove second (v2, from comments)
def ignoreten(h):
indices = [i for (i,v) in enumerate(h) if v == 10]
for i in reversed(indices[1:]):
del h[i]
From your comment asking about removing all non-initial occurrences of 10, if you're looking for in-place modification of h, then you almost definitely want something like this.
The first line collects all the indices of 10 into a list.
The second line is a bit tricky, but working inside-out it:
[1:] "throws out" the first element of that list (since you want to keep the first occurrence of 10)
reversed iterates over that list backwards
del h[i] removes the values at those indices.
The reason we iterate backwards is because doing so won't invalidate the rest of our indices that we've yet to delete.
In other words, if the list h was [1, 10, 2, 10, 3, 10], our indices list would be [1, 3, 5].
In both cases we skip 1, fine.
But if we iterate forwards, once we delete 3, and our list shrinks to 5 elements, when we go to delete 5 we get an IndexError.
Even if we didn't go out of bounds to cause an IndexError, our elements would shift and we'd be deleting incorrect values.
So instead, we iterate backwards over our indices, delete 5, the list shrinks to 5 elements, and index 3 is still valid (and still 10).
With list.index
def ignoreten(h):
try:
second_ten = h.index(10, h.index(10)+1)
del h[second_ten]
except ValueError:
pass
The inner .index call finds the first occurrence, the second uses the optional begin parameter to start searching after that. Wrapped in try/except in case there are less than two occurrences.
⇒ Personally, I'd prefer these in the opposite order of how they're listed.
[1] You're iterating over a weird subset of the list with your arguments to range. You're skipping (not applying your "is 10" logic to) the first and last two elements this way.
Bonus: Walrus abuse
(don't do this)
def ignoreten(h):
x = 0
return [v for v in h if v != 10 or (x := x + 1) != 1]
(unlike the previous versions that operated on h in-place, this creates a new list without the second occurrence of 10)
But the walrus operator is contentious enough already, please don't let this code out in the wild. Really.

Python for loop multi-dimensional array indexing issue

I have the first two strings in a string list strs that is guaranteed to have length of at least 2. I want to compare their letters against each other, and perform a task when their letters are identical. Here is the code I am using:
iter_len = len(strs[1])
if (len(strs[0]) >= len(strs[1])):
iter_len = len(strs[0])
for i in range (0, iter_len, 1):
if (strs[0][i] == strs[1][i]):
[do a thing]
However, when I run this, I get a IndexError: string index out of range for the if (strs[0][i] == strs[1][i]): line. I don't quite understand why this is happening, as the first if statement should ensure that iter_len is the minimum length between strs[0] and strs[1], and should prevent the index from going over. Any advice is much appreciated.
If you need to iterate through two sequences in lockstep, it's generally best practice to use zip:
for a,b in zip(strs[0], strs[1]):
if a == b:
#[do a thing]
This will deal with the issue of one sequence being longer than the other.
If you need the index, you can use enumerate with your zip:
for i, (a, b) in enumerate(zip(strs[0], strs[1])):
if a == b:
#[do a thing with i]

Unexpected error: "IndexError: list index out of range" when trying to access a list within a function

def myMax(L):
print(L)
f=len(L)
ind=0
maxx=L[0]
for i in range(len(L)):
if L[i]>maxx:
maxx=L[i]
ind=i
return (ind,maxx)
print(myMax([1, 2, -9, 10]))
print(myMax([]))
I am quite new to python. Above is code that I have written which takes a list as input and returns a tuple with the index of the highest number and the highest number itself.
For some reason I am getting an "IndexError:list index out of range" on line 5, where "maxx=L[0]"
Any help would be appreciated
You pass empty list : myMax([]) to the function and you point to the first element of this empty list L[0]. You need to check if the list L is not empty.
Adding the below as the first lines of the function will help you to protect against None or empty list
if L is None or len(L) == 0:
raise ValueError('Input list can not be None or empty')
Because you are calling the function on an empty list on the last line of your code.
print(myMax([]))
The argument you are passing to myMax function is [] that have length of zero.
When you call the fifth line your are actually trying to access the first element of the list, that does exist. In fact list in Python are indexed from 0 to n - 1 where n is the size of the list.
By default when you try to access an array on an index that it does not contain, the interpreter raise the exception IndexError: list index out of range. There are several ways to handle this cases for example the try except control, but in your case since the function in returning an integer I suggest you to append a control at the very end in order to return -1 in such cases.
def myMax(L):
if len(L) == 0:
return -1
# your code here
In this way you will not try an out of bound access and you have a return code representing the error occurred.

Modifying specific array elements in Python 3.1

I have two arrays: array and least_common (filter array)
The following code iterates through array, checks for elements that match least_common, and if finds it, modifies it and appends it to a new array.
for i in range (len(array)):
for j in range(len(least_common)):
if array[i] is least_common[j][0]:
new_array.append ((array[i]) + (array[i] * (mod[1]/100)))
However, if the element in array does not match any of the elements in least_common I wan't to append it to new_array, then iterate to the next element in array to begin the checking process again.
This code is a bit wonky to me -- I think you want to start with something more like:
lookup = set([x[0] for x in least_common])
new_array = []
for elem in array:
if elem in lookup:
new_array.append(elem + (elem * (mod[1]/100)))
else:
new_array.append(elem)
In Python, what you are trying to do is done using lists. There is another separate data type called arrays, but that is for totally different purpose. Please don't confuse and use the proper terminology, list.
Lists can be iterated through. You need to not index the elements out of the list and then access them using the index. That is C or C++ way of doing things and not python.
You use a list or a dictionary called mod in your original code. It is a bad idea to override builtin names. I tried to understand what you are trying, came up with the following code. Take it further, but before that, I think some beginner tutorials might help you as well.
new_array = []
somevalue = 0.001
for elem in array:
for anotherelem in least_common:
if elem == anotherelem[0]:
new_array.append(elem + (elem * somevalue))
Keep track of whether you found a match using a boolean, which you set to False before each inner loop and set to True within your if. After each iteration, if it's still False it means you found no matches and should then do your appending.
You should also follow what #Andrew says and iterate over lists using for a in array:. If you need the index, use for i, a in enumerate(array):. And be aware that is is not the same as ==.
new_array = []
for array_item in array:
found = False
for least_common_item in least_common:
if array_item is least_common_item:
found = True
if not found:
new_array.append (array_item * (1 + mod[1]/100))
You can also greatly shorten this code using in if you meant to use == instead of is:
for array_item in array:
if array_item not in least_common:
new_array.append (array_item * (1 + mod[1]/100))
Why not this:
least_common_set = frozenset(x[0] for x in least_common)
for e in array:
if e is not in least_common_set:
new_array.append(e + (e * (mod[1]/100)))
If I understand correctly your problem, here is a possible solution:
for e in array:
for lc in least_common:
if e is lc[0]:
new_array.append(e + e * (md[1] / 100))
break
else:
new_array.append(e)
The else clause in the for loop is executed when the loop terminates through exhaustion of the list, but not when the loop is terminated by a break statement.
Note that there is no need to use range or len, in Python you can just iterate on the elements of a sequence without involving indexes - you may use enumerate for that, but in this case you don't need to. Also, please don't use built-in names such as mod for your variables: here, I have renamed your dictionary md.

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