Python: For loop not working - python

Why is the for loop not working?
l=[1,2,3,4,5]
def times(x):
for i in len(x):
x[i]+=10
times(l)
print l
Ideally it should print the elements of the list incremented by 10. But it is giving me the following error:
Traceback (most recent call last):
File "ex1.py", line 5, in <module>
times(l)
File "ex1.py", line 3, in times
for i in len(x):
TypeError: 'int' object is not iterable
Where am I going wrong?

len function will return just the length of the list. Its just a number, so you cannot iterate it with the for loop.
Perhaps you wanted to use the xrange function, along with the len(x)
for i in xrange(len(x)):
We use xrange function here, because range function will create the entire list in memory before iterating. For example,
print range(10)
will give you the newly constructed list with elements from 0 to 9. Think about iterating a very big list. Lets say that the list's size is 10000000. It is really a waste of memory to generate numbers from 0 to 10000000, just for the sake of iterating, right? Thats why we use xrange.
xrange returns an iterable object which gives one number at a time while iterating. Its very memory efficient, as we don't have to construct the entire list.
Suggestion: Unless it is absolutely necessary to modify the original list, you can create a new list and return it.
def times(my_list, my_num = 10):
return [current_num + my_num for current_num in my_list]
l = [1,2,3,4,5]
l = times(l)
print l
It will have the same effect on the data, as the first one. But we use list comprehension to create a new list and we assign it to the variable l. So, now l points to the newly generated list instead of the old list.

This is because len(x) is just an integer, you need to create a list, e.g.
l=[1,2,3,4,5]
def times(x):
for i in range(len(x)):
x[i]+=10
times(l)
print l

Related

How to solve the error list index out of range ? (On python using pygame and sys) [duplicate]

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.

function to add elements in list

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 (=).

Facing an issue in removing duplicate entries in a list of my python Program

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

Variation of suffix array in python

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

TypeError: 'int' object is not iterable, why it's happening

Here is three examples actually.
>>> result = []
>>> for k in range(10):
>>> result += k*k
>>> result = []
>>> for k in range(10):
>>> result.append(k*k)
>>> result = [k*k for k in range(10)]
First one makes a error. Error prints like below
TypeError: 'int' object is not iterable
However, second and third one works well.
I could not understand the difference between those three statements.
In-place addition on a list object extends the list with the elements of the iterable. k*k isn't an iterable, so you can't really "add" it to a list.
You need to make k*k an iterable:
result += [k*k]
result is a list object (with no entries, initially).
The += operator on a list is basically the same as calling its extend method on whatever is on the right hand side. (There are some subtle differences, not relevant here, but see the python2 programming FAQ for details.) The extend method for a list tries to iterate over the (single) argument, and int is not iterable.
(Meanwhile, of course, the append method just adds its (single) argument, so that works fine. The list comprehension is quite different internally, and is the most efficient method as the list-building is done with much less internal fussing-about.)
You are iterating over an integer rather than a string or sequence.
For result += k*k,only if k was a string/sequence input,then it would be true but if k is a number, result would be a continued summation.
For result.append(k*k),whether k is a string or number,result gets sequentially additions.
I know this is too old but for anyone who lands here, this is a simple reproducible example to illustrate ''int' object is not iterable' error.
lst1 =[3,4,5,6]
def square(lst1):
lst2 = []
for num in lst1:
lst2.append(num**2)
return lst2
#print(list(map(square,lst1))) # this will raise ''int' object is not iterable'
print(list(map(square,list(lst1)))) # here making lst1 as list of list fixs the iterable problem i.e lst1 =[[3,4,5,6]]

Categories

Resources