I'm creating a program that adds the elements of the same cardinality in two separate lists:
list1 = [1,2,3]
list2 = [2,3,4]
Thus list3 would be [3,5,7]
This is the code I have:
def add_list(lst1,lst2):
sum_lst = []
index = 0
while (len(lst1)-1) >= index:
sum_lst[index] == lst1[index] + lst2[index]
index += 1
return sum_lst
I get this error "index out of range" when I run it:
sum_lst[index] == lst1[index] + lst2[index]
How is it out of range considering that I stop the index before it reaches past the length of the list?
sum_lst[index] == lst1[index] + lst2[index]
^1 ^2
2 main issues:
you initialize sum_lst as '[]` which means, YES, 0 IS out of index.
== is not the same as =. == is a boolean expression operation that asses equality whereas = is the assignment operator.
two fixes:
#replaces that one line
sum_lst.append(lst1[index]+lst2[index])
OR
#replaces the whole function
sum_lst = [x+y for x,y in zip(lst1,lst2)]
The reason you're running into your error message is because sum_lst doesn't yet have the indices you're looking for.
E.g. if you try
>>> some_list = []
>>> some_list[0] = 1 # you'll get
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
Instead, try something like:
sum_lst.append(lst1[index] + lst2[index])
This'll add a new element to the end of the array
The problem with this line was already pointed out:
sum_lst[index] == lst1[index] + lst2[index]
In addition to this fix, I'm going to explain a few steps you could take to improve this code and similar code.
Instead of incrementing an index and using a while loop, it's common practice to use a for loop in Python. We can use the range function to loop over all indexes.
Here's an improvement (note we fixed append and the == issue here):
def add_list(lst1, lst2):
sum_lst = []
for index in range(len(lst1)):
sum_lst.append(lst1[index] + lst2[index])
return sum_lst
But that still isn't idiomatic.
It would be even better to use the enumerate function to loop over items while retrieving their indices. Whenever you see something like for i in range(len(lst1)) think enumerate.
def add_list(lst1, lst2):
sum_lst = []
for index, item1 in enumerate(lst1):
sum_lst.append(item1 + lst2[index])
return sum_lst
The only reason we need the index is because we're trying to loop over two lists at once. Whenever you need to loop over multiple lists at the same time, you can use the zip function to zip iterables/lists together:
def add_list(lst1, lst2):
sum_lst = []
for item1, item2 in zip(lst1, lst2):
sum_lst.append(item1 + item2)
return sum_lst
This is nearly the best we could do. There's just one more improvement we could make: use a list comprehension instead of a for loop:
def add_list(lst1, lst2):
return [item1 + item2 for item1, item2 in zip(lst1, lst2)]
>>> [a+b for a,b in zip(list1,list2)]
[3, 5, 7]
I'd say the main problem with your code isn't the bug itself, it's that you're writing in a traditionally procedural pattern. Perhaps you used to do Java or C? Python is a multi-paradigm language, and supports functional programming. The main takeaway is that you should try to keep things immutable, so instead of creating empty lists and gradually populating them with content, try to create the resulting list on the fly. As in the example above. That way you won't be able produce indexing errors on either side of the assignment operator.
But, if you really want to know, your bug is two-fold:
>>> a = []
>>> a[1] = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
I.e. you can't append things to a list by assigning to a new element. You could do it this way instead:
a += [3]
Secondly you've used a comparison operator (==) instead of the assignment operator (=).
Related
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.
How can I resolve this IndexError? I tried by using a while loop, but nothing changed.
Here is my code, it should check the length of the object of two lists (la, lb) and remove the string from la if the string is shorter than the lb string and vice versa. Plus it has to remove both of the strings if their length is the same.
def change(l1, l2):
la1 = l1[:]
la2 = l2[:]
i = 0
for i in range(len(la1)):
if la1[i] == la2[i]:
l1.pop(i)
l2.pop(i)
elif la1[i] > la2[i]:
l2.pop(i)
elif la2[i] > la1[i]:
l1.pop(i)
Assuming your lists are of equal lengths
As has been pointed out in the comments, the IndexError happens due to your lists' length changing when you pop() an item.
Since you're iterating over your list using a range(len(l)) in a for loop, which isn't updated after every completed loop, you'll eventually hit an index that's out of range.
An example, which you can try easily enough yourself:
l = [1,2,3,4,5,6,7,8,9,10]
for i in range(len(l)):
l.pop(i)
print("Length of list", len(l))
Do not confuse yourself by calling print(range(len(l)) in the for loop - this will give you an updated range, but is misleading. The range in the for loop is only called once, hence never updates while iterating.
A different approach
Instead of working with indices, try using zip() and building new lists, instead of changing existing ones.
def change(l1, l2):
new_l1 = []
new_l2 = []
for a, b in zip(l1, l2):
if len(a) == len(b):
continue # do nothing
elif len(a)<len(b):
new_l2.append(b)
elif len(a)>len(b):
new_l1.append(a)
return new_l1, new_l2
This approach, essentially, generates the same list you create using pop(), while avoiding usage of indices.
Note that zip() will stop once it reaches the end of the smaller of both iterables. If your lists may not be of equal length, and you'd like to iterate until the longest of both iterables is iterated over entirely, use zip_longest(). But I do not think this is what you need in this case.
Additional Notes
You would also run into a problem if you were to iterate over your list using the following code:
l = [i for i in range(10)]
for item in l:
l.remove(item)
>>>[1, 3, 5, 7, 9]
Essentially, it's not advisable to iterate over any iterable while changing it. This can result in anything from an Exception being thrown, to silent unexpected behaviour.
I'm aware you were avoiding this by looping over the copies, I just wanted to add this for posterity.
You can traverse the lists backwards, so that when you remove an item from the list the indices of the elements that you have not examined yet won't be affected
def f(a, b):
l = len(a) if len(a)<len(b) else len(b)
for i in range(l):
j = l-i-1
la, lb = len(a[j]), len(b[j])
if la<lb: a.pop(j)
elif lb<la: b.pop(j)
else: a.pop(j), b.pop(j)
return a, b
ps I staid faithful to your problem statement and not to your implementation re the comparison based on strings' lengths.
if you want to iterate over a list and want to empty it
but don't want pop index error use this:
lst = [ 1, 4, 56, 2, 4 , 12, 6, 89 ,11, 0]
i =0
while len(lst) != 0:
lst.pop(0)
i+=1
print(lst)
seq_sum = []
for i in range(len(sequence)):
seq_sum[i] = sequence[i] + inv_sequence[i]
print (seq_sum)
When I try to run this code it return an error: list assignment index out of range. How can I fix the problem?
sequence and inv_sequence are arrays of integers.
seq_sum[i] will raise an IndexError as the seq_sum list is empty. You should use append instead:
seq_sum = []
for i in range(len(sequence)):
seq_sum.append(sequence[i] + inv_sequence[i])
print(seq_sum)
You can achieve the same result with a prettier code using list comprehension:
seq_sum = [seq_elem + inv_elem for seq_elem, inv_elem in zip(sequence, inv_sequence)]
You could also use map but some would argue its readability:
import operator
seq_sum = list(map(operator.add, sequence, inv_sequence))
You've declared seq_sum to be an empty list. You then try and index in a position other than 0 which results in an IndexError.
Expanding a list to make it larger is essentially done with appending, extending or slice assignments. Since you sequentially access elements, seq_num.append is the best way to go about this.
That is:
seq_sum[i] = sequence[i] + inv_sequence[i]
Should be instead changed to:
seq_sum.append(sequence[i] + inv_sequence[i])
The below program is for entering the values to a list and print the list again after removing the duplicate entries... Can someone please have a look and let me know what would be the error in the program?
print ("Enter the Numbers into List \n")
list = []
n = int(input(""))
while n <= 1000:
list.append(n)
n = int(input(""))
m = len(list)
for i in range (0,m-1):
for j in range (i+1,m):
if list[i] == list[j]:
list.remove(j)
else:
pass
print (list)
When I run the program it gives below error:
File "python", line 23, in <module>
ValueError: list.remove(x): x not in list
There are several problems with your code.
The first is your assumption that list.remove() takes an index as its argument. It doesn't remove an element by index, but by value (see the method's documentation). The second is that if you modify a list as you iterate over it you may well find that this messes up your indexing:
>>> for i in range(len(lst)):
... if i == 2:
... del lst[i]
... else:
... print(lst[i])
...
1
2
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
IndexError: list index out of range
The third (minor) issue is that you are using the name of a built-in type (list) as a variable in your code, which will "shadow" the built-in type, making it inaccessible.
There are a number of problems in your solution:
The one you run into is that the remove method removes the first element that matches the argument, but you use the index of the element as argument which does not need to be one of the element. Instead if you want to remove an element by index you should use del mylist[index] instead.
Second you're trying to modify an list while iterating through it and that's not a good thing, you will probably not getting the result from that that you expect.
Also a aestetically questionable construct is calling your list list, that name is already used by the type list. By doing so you run into the problem that you can't use the builtin list anymore and that could be confusing.
The pythonic way to do this is to use the library functions and not reinventing the wheel (and of course not calling your list list):
import collections
mylist[:] = list(collections.OrderedDict.fromkeys(mylist).keys())
What it does is using OrderedDict which retains the order of the keys to put the element into and then create a list from that and then put it in the original list.
That solution however assumes that the items are hashable, which might not be the case. Otherwise the only solution is to iterate twice through the list as Cunningham's answer shows (which is therefore slower).
You are trying to remove j not what is in list[j], you also need to make a copy of the list and remove from that, when you remove elements you change the size of the list so apart from an index error you will try to remove elements that are not there:
m = len(lst)
out = lst[:]
for i in range(m - 1):
for j in range(i + 1, m-1):
if lst[i] == lst[j]:
out.remove(lst[j])
print(out)
To remove from the original list, you can use a set and reversed:
seen = set()
for ele in reversed(lst):
if ele in seen:
lst.remove(ele)
seen.add(ele)
print(lst)
Or use an OrderedDict:
from collections import OrderedDict
print(list(OrderedDict.fromkeys(lst).keys()))
A simple way using comprehension would be assuming your list name is l to avoid clashing with the type list:
l = [ l[i] for i in range(len(l)) if l[i] not in l[:i] ]
It avoids a name clash with the builtin type list, and modifying a list that you are iterating, and is still O(n2/2)
as you keep deleting the elements the length of list keeps decreasing and the index you are accessing might not be accessible
instead do something like
list(set(t))
and dont name your lists as the "list" keyword
I'm relatively new to computer science, and I'm learning how to code in python. I'm trying to figure out how to make a function that takes a list and returns a list of suffixes from the inputted list, in order from shortest length to longest length. For example, entering
[3,4,2,-9,7,6,1]
to the function would return
[[],[1],[6,1],[7,6,1],[-9,7,6,1],[2,-9,7,6,1],[4,2,-9,7,6,1],[3,4,2,-9,7,6,1]]
I've tried several approaches, but so far I'm not having much luck. Here is what I have so far:
def h(m):
newlist = []
x = 0
y = (len[m])-1
while x in range(y):
sublist = []
sublist = sublist + m[x:y]
newlist.append(sublist)
x += 1
return new list
When I try to run the function by entering something like
a = [3,4,2,-9,7,6,1]
h(a)
I get an error:
Traceback (most recent call last):
File "<pyshell#239>", line 1, in <module>
h(a)
File "<pyshell#238>", line 4, in h
y = (len[m])-1
TypeError: 'builtin_function_or_method' object has no attribute '__getitem__'
My objective with this bit of code was simply to create a the list of suffixes without sorting them by length. After I figure out how to create this new list I will add the sorting bit of the code. Keep in mind this is not a homework assignment. Any help would be greatly appreciated!
Possible solution is using list comprehension:
[l[i:] for i in range(len(l), -1, -1)]
This code uses slicing and list comprehension to simply return a list of slices from the end. Using your code, small modification is required - len is a function and not a dictionary, therefore you need to use the call operator () instead of subscript operator [].
y = len(m) - 1
That will not yield correct result though, because you will not get the last suffix and empty suffix. In order to cover these two, you will need to modify y or the loop to cover them
y = len(m) + 1
or better
while x in range(y + 1):
use parenthesis to get the length of the list:
y = len(m) - 1
Your error is in your len:
(len[m]) - 1
len is a function, and you can't index or slice or the what not. Do this instead:
y = len(m) - 1
There's also one other error:
return new list
Should be: (You can't have spaces in variables)
return newlist