python for loop with lists - python

I get:
if(lst[i]%2!=0):
IndexError: list index out of range
from this code:
lst=[1,2,3,4,5,6]
for i in range(len(lst)):
if(lst[i]%2!=0):
lst.remove(lst[i])
print(lst)
I am trying to print only the even numbers in a list and I do not see a problem with my code
why am I getting this error ?

You should not remove from a list while iterating it. Use, for instance, a list comprehension and slice assignment to achieve the same modification:
lst = [1,2,3,4,5,6]
lst[:] = [x for x in lst if x % 2 == 0]
# or simply (if you don't need to mutate the original list)
# lst = [x for x in lst if x % 2 == 0]
print(lst)
# [2, 4, 6]
This has also better time complexity (linear) whereas the repeated remove approach is quadratic.

Instead of removing the item from the original list, you can also split the original list into 2 new lists, evens and odds
lst=[1,2,3,4,5,6]
evens = []
odds = []
for i in lst):
if(i % 2 != 0):
odds.append(i)
else:
evens.append(i)
print(evens)

Related

remove even elements from a list. Showing list index out of range

image
please refer to the image.
I want to create a list(say [1,2,3,4,5]). The code checks the divisibility by 2 of every element of the list one by one. if it is divisible by 2, it removes the those elements and returns a list of odd numbers . Please try to keep the code as simple as possible as i am just a beginner....
The problem with your code is that once you remove the even number from the list, It reduces the length of the list. So in the second iteration of your code, 2 is removed from the list l = [1,2,3,4,5] which modifies the list l to [1,3,4,5], so now, the length of the list is 4 instead of 5. But the for loop, which will run for the values "0, 1, 2, 3, 4" (because of variable x, which is 5), your code produces that error.
To solve this error, you can create a new list and append the even numbers in it.
It's a lot easier and more Pythonic to build a new list of the odd numbers than it is to modify the original list to remove the even numbers.
If you understand list comprehensions, there's a simple answer.
l = [1, 2, 3, 4, 5]
l2 = [x for x in l if x%2 == 1]
print(l2)
You can also do it imperatively:
l = [1, 2, 3, 4, 5]
l2 = []
for x in l:
if x%2 == 1:
l2.append(x)
print(l2)
Either solution will print [1, 3, 5].
l = [1,2,3,4,5]
x = len(l)
new_l = []
for a in range(x):
if l[a]%2!=0:
new_l.append(l[a])
new_l
Use the above code instead of removing elements from list create a new one.
I took a look at the image and couldn't figure out much. Going by your definition
l = [1,2,3,4]
for i in l:
if i % 2 == 0: # check if i is divisible by 2
l.remove(i) # remove the item if the number passes above check.

How to remove an item while iterating over a list? [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 5 months ago.
My code looks like this:
def nue(li):
for i in li:
li.remove(i)
print(li)
li = [1, 2, 3]
nue(li)
However, running this results in:
>>> [2]
More generally, how do I remove the i-th position on a list while iterating over the list (for reasons it failed some test in a nested loop or something like that)?
you can do like this
def nue(li):
for i in li[:]:
li.remove(i)
print(li)
li = [1, 2, 3]
nue(li)
li[:] will clone original li
Try list comprehension:
def remi(slist, i): # remi means REMove I
return [slist[j]
for j in range(len(slist))
if j != i]
print(remi ([1,2,3,4], 2))
Output:
[1, 2, 4]
Why not just use a list comprehension instead of removing items from an existing list?
old_list = [1,2,3,4,5]
li = [1,2,3]
new_list = [i for i in old_list if i not in li]
If you don't want to use a list comprehension you can try the filter function
old_list = [1,2,3,4,5]
li = [1,2,3]
new_list = list(filter(lambda x: x not in li, old_list))
You might want to consider going over the array in reverse. The following code demonstrates three functions that do the same thing. All are called prune and are interchangeable. By looking at an array in reverse order, you avoid changing the index of values you will examine in the future.
#! /usr/bin/env python3
def main():
array = list(range(20))
print(array)
prune(array, lambda value: value % 3)
print(array)
def prune(array, del_condition):
for index, value in reversed(tuple(enumerate(array))):
if del_condition(value):
del array[index]
def prune(array, del_condition):
for index in range(len(array) - 1, -1, -1):
value = array[index]
if del_condition(value):
del array[index]
def prune(array, del_condition):
for index in reversed(range(len(array))):
if del_condition(array[index]):
del array[index]
if __name__ == '__main__':
main()

How to create list of all possible lists with n elements consisting of integers between 1 and 10?

I'm trying to create a set of test cases for a project I'm working on, and I'd like to create all possible test cases and iterate through them (quick program, shouldn't take long). The test cases should all be a list of length 1-4 and each item on the list should be an integer between 0-10, inclusive. The first item on the list should be 0. The set of lists would then be:
[0]
[0,0]
[0,1]
[0,2]
[0,3]
...
[0,10]
[0,0,0]
[0,0,1]
[0,0,2]
[0,0,3]
...
[0,1,0]
[0,1,1]
[0,1,2]
...
[0,10,10]
...
[0,10,10,10]
This is what I have so far, but it's not outputting the correct lists:
test_list = [0]
for length in range(2, 5):
while len(test_list) < length:
test_list.append(0)
for position in range(1, length):
for digit in range (0, 11):
test_list[position] = digit
print test_list
or you could generate the lists with a generator; this way you would not have the whole list in memory:
from itertools import product
def gen():
yield [0]
for i in range(11):
yield [0, i]
for i, j in product(range(11), range(11)):
yield [0, i, j]
for i, j, k in product(range(11), range(11), range(11)):
yield [0, i, j, k]
for item in gen():
print(item)
this seems pretty readable to me but is not extensible (in case you need longer lists) as other answers here.
therefore here the version where the length of the list is tweakable:
from itertools import product
def gen(length):
for l in range(length):
for tpl in product(range(11), repeat=l):
yield (0,) + tpl
for item in gen(length=4):
print(item)
this version now returns tuples and not lists. in case this matters you can surrout the return values with list().
I would use itertools.product on lists of size 2, 3, 4 in a nested loop
import itertools
test_list = [0]
for i in range(1,4):
args = [list(range(0,11))] *i
test_list += [[0]+list(x) for x in itertools.product(*args)]
# display list
for t in test_list:
print(t)
A memory efficient one-liner :
import itertools
size = 4
for x in map(list, itertools.chain(*(itertools.product([0], *[range(11)]*i) for i in range(size)))):
print(x)
You can modify 4 with any other list size :)

Adding two lists while checking length

I'm stuck on a question where I have to add 2 lists together while factoring in the length. For example, if list1 = [1,2] and list2 = [3,4,5] the answer would be [1+3,2+4,5] or [4,6,5].
What I have so far is:
def addsum(list1,list2):
new_list = []
if len(list1) > len(list2):
new_list = list1[0:]+list2[0:]
I'm not really sure how to appraoch this question since I'm new to lists. Would appreciate the help!
You should use zip_longest from itertools with a fillvalue of 0 in a list comprehension:
r = [sum(i) for i in zip_longest(list1, list2, fillvalue=0)]
zip_longest pairs the elements in the input lists (list1 and list2 here). If one list is smaller, pairs the remainding elements of the larger list with the value supplied as the fillvalue (which we assign to 0 here).
Now, r equals:
print(r) # [4, 6, 5]
Similarly, you could utilize map instead of the list-comp:
# Python 3.x
r = list(map(sum, zip_longest(list1, list2, fillvalue=0)))
# Python 2.7
r = map(sum, zip_longest(list1, list2, fillvalue=0))
and get the same result for r.
Poor man's approach:
def addsum(list1,list2):
if len(list1) >= len(list2):
for i in range(len(list2)):
list1[i]=list1[i]+list2[i]
return list1
else:
for i in range(len(list1)):
list2[i]=list1[i]+list2[i]
return list2
I would use the zip_longest solution too, but building in your code this is what I would do
def addsum(list1, list2):
if len(list1) < len(list2):
list1, list2 = list2, list1
result=list(list1)
for i,x in enumerate(list2):
result[i] += x
return result
first make sure that the first list is the longest, and if that is not the case exchange them, then make a copy of longest list and finally add the elements of the shorter list position-wise to the copy and return it
>>> addsum([1,2],[3,4,5])
[4, 6, 5]
>>>
Although zip_longest is more neat, another possibility is to use a trial/error approach (if you are tired of "ifs"), as shown here:
def addsum(list1, list2):
res = []
i = 0
while i < len(list1) or i < len(list2):
try:
res.append(list1[i]+list2[i])
except IndexError:
try: res.append(list1[i])
except IndexError: res.append(list2[i])
i += 1
return res
Documentation on zip_longest:
Make an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted.
Here's the code:
from itertools import zip_longest
[x + y for x, y in zip_longest([1,2], [3,4,5], fillvalue=0)]
Output:
[4, 6, 5]

Python list recursive changes

I have a bug in my attempt to add to a list a sequence of numbers recursively. E.g. if the input is [5,3,9], I do [5+1,3+2,9+3] and output [6,5,12]. I want to do this recursively so the way I'm doing it is going through and adding one to a smaller and smaller part of the list as below:
def add_position_recur(lst, number_from=0):
length = len(lst)
# base case
if (length <= 1):
lst = [x+1 for x in lst]
print "last is", lst
else:
lst = [x+1 for x in lst]
print "current list is", lst
add_position_recur(lst[1:], number_from)
return lst
The problem, though, is that all this does is add 1 to every element of the list. Where is the bug? Is it to do with the way I return the list in the base case?
When you recurse down your call stack you slice lst which creates a new list, this is not the same as what you return, so you will only ever return the changes you've applied to your list in the first call to the function, losing all changes further down the stack:
>>> add_position_recur([1,2,3])
[2, 3, 4]
This should have returned [2, 4, 6].
You need to consider reassembling the list on the way out to get the changes.
return [lst[0]] + add_position_recur(lst[1:], number_from)
and you need to return lst in your base case:
def add_position_recur(lst, number_from=0):
length = len(lst)
# base case
if (length <= 1):
lst = [x+1 for x in lst]
return lst
else:
lst = [x+1 for x in lst]
return [lst[0]] + add_position_recur(lst[1:], number_from)
>>> add_position_recur([1,2,3])
[2, 4, 6]
However, this is quite a complicated approach to this recursion. It is idiomatic for the base case to be the empty list, otherwise take the head and recurse down the tail. So something to consider which uses the number_from:
def add_position_recur(lst, number_from=1):
if not lst:
return lst
return [lst[0]+number_from] + add_position_recur(lst[1:], number_from+1)
>>> add_position_recur([1,2,3])
[2, 4, 6]
This also has the advantage(?) of not changing the passed in lst
Why don't you instead do something like this:
def func(lon, after=[]):
if not l:
pass
else:
v = len(lon) + lon[-1]
after.append(v)
func(lon[:-1], after)
return after[::-1]
The output of the function for the example you provided matches what you want.
Currently, you are simply adding 1 to each value of your list.
lst = [x+1 for x in lst]
Rather, you should be increasing a variable which is being added to x with each iteration of x in lst.
lst = [x+(lst.index(x)+1) for x in lst]
This solution assumes that you want the number being added to x to depend on its position in the list relative to the start of the list, rather than being dependent on the position of x relative to the first element which was >1. Meaning, do you want to add 1 or 3 to the value 2 in the following list? The solution above adds three.
lst = [0.5, 0.1, 2, 3]

Categories

Resources