List Index out of range error. Python - python

lst = []
for i in range(1,13196):
if 13195 % i == 0:
lst.append(i)
for k in range(len(lst)):
for j in range(1,lst[k]):
if lst[k] % j != 0:
lst.remove(lst[k])
print(lst)
When I run this code, it says if lst[k] % j != 0: List index out of range.
Can anyone tell me what I did wrong ?

You are iterating over a range of the current length of lst. Every time you do lst.remove(lst[k]), the lst gets shorter, so the range you were using becomes unsuitable. For example, if you start with 8 elements, it goes from indices of 0 to 7 inclusive, but if you remove an element, the last index will then be 6, not 7.
The easiest way to fix this is to simply create a new list:
lst = []
for i in range(1,13196):
if 13195 % i == 0:
lst.append(i)
result = lst[:] # create a copy to work with
for k in range(len(lst)):
for j in range(1,lst[k]):
if lst[k] % j != 0 and lst[k] in result: # check that it's there before removal
result.remove(lst[k])
print(result)
That said, this code eliminates every number which cannot be evenly divided by every positive integer smaller than that number, which understandably produces a result of [1]. If that's not what you wanted, you'll have to take another look at your algorithm.

lst = []
lst2 = []
for i in range(1,13196):
if 13195 % i == 0:
lst.append(i)
lst2.append(i)
for k in range(len(lst)):
for j in range(1,lst[k]):
if lst[k] % j != 0:
lst2.remove(lst[k])
print lst2
Give this a try. Your problem is that you were iterating over the value of the original list. When you removed parts of the original list, the length of this value shortened, but the for loop will not account for it.

Related

Sum of lowest numbers that are part of an arithmetic sequence

I would like to iterate through a list of integers, calculate the sum of the lowest numbers that belongs to an arithmetic sequence with common difference 1 + the numbers that are not part of a sequence:
mylist = [2,3,4,10,12,13]
So, from mylist it would be 2 (from 2,3,4) + 10 (not part of a sequence) + 12 (from 12,13)
I've managed to make something work, but I could only figure out how to do it, if the list is reversed. And I am sure there is a better/cleaner solution that mine:
mylist = [13,12,10,4,3,2]
result = mylist[-1] #if I don't do this, I don't know how to grab the last item in the list
for i in range(len(mylist)-1):
if mylist[i] - mylist[i+1] == 1:
continue
else:
result += mylist[i]
Hope someone will help me out, and that I get a little wiser in my coding journey. Thanks.
#KennethRasch - earlier post would work. Alternatively, you can do this as well:
Try to find each possible subsequence's starting numbers as starts then just sum them to get answer.
L = [13,12,10,4,3,2]
L.sort()
starts = [x for x in L if x-1 not in L]
print(starts)
result = sum(starts)
print(result) # 24
Alternatively, you can put this into a function for future re-use it:
def sum_lowests(L):
'''L is a numbers sequence '''
L.sort()
starts = [x for x in L if x-1 not in L]
#ans = sum(starts) # can skip this step; just to make it clear
return sum(starts)
if __name__ == '__main__':
L = [13,12,10,4,3,2]
A = [1, 2, 3, 5,6, 9,10,11, 16]
print(sum_lowests(L))
print(sum_lowests(A)) # 31
Keep a running sum, a running index, and iterate while it's still a sequence:
mylist = [13,12,10,4,3,2]
mylist.sort() # this way sequences will be contiguous in the list
cur_index = 0
cur_sum = 0
while cur_index < len(mylist):
# add the current element to the sum
cur_sum += mylist[cur_index]
# now iterate through while it's a contiguous sequence
cur_index += 1
while cur_index < len(mylist) and mylist[cur_index] == mylist[cur_index - 1] + 1:
cur_index += 1
print(cur_sum)

Using a loop to describe multiple conditions

In the following code, I am trying to extract numbers from a list in which all digits are divisible by 2. The following code works.
l = range(100,401)
n=[]
for i in l:
s =str(i)
if all([int(s[0])%2==0,int(s[1])%2==0,int(s[2])%2==0]):
n.append(s)
print(",".join(n))
I was trying to insert a for loop to avoid writing all three conditions explicitly.
l = range(100,401)
n=[]
ss=[]
for i in l:
s =str(i)
ss.append(s)
for element in ss:
for j in range(3):
if int(element[j])%2==0:
n.append(element)
print(n)
I can't get the desired output. Not only that, the elements of output list 'n' at even index are printed twice. I am unable to figure out WHY?
Thanks.
Generator expression checking if all() elements evaluate to True comes to your rescue:
l = range(100,401)
n=[]
for i in l:
s = str(i)
if all(int(ch) % 2 == 0 for ch in s):
n.append(s)
print(",".join(n))
Now it also works even if you work with more digits.
Thanks for #jpp's advice on generator expression!
And here a faster alternative where you evaluate if any() is not divisable with 2.
l = range(100,401)
n=[]
for i in l:
s = str(i)
if any(int(ch) % 2 != 0 for ch in s):
continue
else:
n.append(s)
print(",".join(n))
You can do this:
l = range(100, 401)
n = []
for i in l:
v = 0
for j in str(i):
if int(j) % 2 == 0:
v += 1
if v == len(str(i)):
n.append(str(i))
print(",".join(n))
Or with some list comprehension:
l = range(100, 401)
n = []
for i in l:
if all(int(j) % 2 == 0 for j in str(i)):
n.append(str(i))
print(",".join(n))
Or with even more list comprehension:
l = range(100, 401)
n = [str(i) for i in l if all(int(j) % 2 == 0 for j in str(i))]
print(",".join(n))
Or with a ridiculous minimizing:
print(",".join([str(i) for i in range(100, 401) if all(int(j) % 2 == 0 for j in str(i))]))
Explaining
OP asked me to explain why his code doesn't work. I'll make it in some steps, also optimizing it:
l = range(100,401)
n = []
ss = []
for i in l: # You don't need this loop, you are just making a new list with string values instead of integers. You could make that on the fly.
s = str(i)
ss.append(s)
for element in ss:
for j in range(3):
if int(element[j]) % 2 == 0: # This only check if the current digit is pair and it append the whole number to the list. You have to check if the 3 numbers are pair AND then append it.
n.append(element)
print(n)
Your code check each digit and if that is true, the number is appended to the result list (n). But you don't want that, you want to check if the 3 digits that make the number are pair, so you have to check the whole group.
For example you could do this:
for element in l:
pairs = 0
for j in range(3):
if int(str(element)[j]) % 2 == 0:
pairs += 1 # Each time a digit of the number is pair, `pairs` variable increase in one
if pairs == 3: # If the 3 digits are true it append your number
n.append(str(element))
That is my first idea of how to improve your code, but instead of element and pairs I use j and v, (also I don't use range(3), I just iterate over the stringed number).
If you are looking for something "better" you could try to use a list comprehension like all(int(j) % 2 == 0 for j in str(i)). That iterate over all the digits to check if the are pair, if all the checks are true (like 222, or 284) it returns true.
Let me know if I should explain something more.
Try this method. You don't need to check all the numbers.
You just need to change the range statement from range(100, 401) to range (100, 401, 2) and add some checks as the Numbers which have first digit as Odd you can skip all the 100 numbers and then in next 10 series you can skip 10 if the tenth digit is odd. It reduces the complexity and decreases your processing time.
l = range(100, 401, 2)
n = []
for i in l:
s = str(i)
if int(s[0]) % 2 == 1:
remainder = i % 100
i = i - remainder + 100 - 1
continue
elif int(s[1])%2 == 1:
remainder = i % 10
i = i - remainder + 10 - 1
continue
n.append(s)
print(",".join(n))

Insertion sort doesn't sort

I have attempted to create an insertion sort in python, however the list returned is not sorted. What is the problem with my code?
Argument given: [3, 2, 1, 4, 5, 8, 7, 9, 6]
Result: 2
1
3
6
4
7
5
8
9
Python code:
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
posfound = 0 #defaults to 0
for j in range(len(sorted_list)):
if sorted_list[j] > i:
sorted_list.insert(j-1, i) #put the number in before element 'j'
posfound = 1 #if you found the correct position in the list set to 1
break
if posfound == 0: #if you can't find a place in the list
sorted_list.insert(len(sorted_list), i) #put number at the end of the list
return sorted_list
You need to change sorted_list.insert(j-1, i) to be sorted_list.insert(j, i) to insert before position j.
insert(j-1, ..) will insert before the previous element, and in the case where j=0 it'll wrap around and insert before the last element.
The Python data structures tutorial may be useful.
As Efferalgan & tzaman have mentioned your core problem is due to an off-by-one error. To catch these sorts of errors it's useful to print i, j and sorted_list on each loop iteration to make sure they contain what you think they contain.
Here are a few versions of your algorithm. First, a repaired version of your code that fixes the off-by-one error; it also implements Efferalgan's suggestion of using .append if an insertion position isn't found.
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
posfound = 0 #defaults to 0
for j in range(len(sorted_list)):
if sorted_list[j] > i:
sorted_list.insert(j, i) #put the number in before element 'j'
posfound = 1 #if you found the correct position in the list set to 1
break
if posfound == 0: #if you can't find a place in the list
sorted_list.append(i) #put number at the end of the list
return sorted_list
Here's a slightly improved version that uses an else clause on the loop instead of the posfound flag; it also uses slice assignment to do the insertion.
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
for j in range(len(sorted_list)):
if sorted_list[j] > i:
sorted_list[j:j] = [i]
break
else: #if you can't find a place in the list
sorted_list.append(i) #put number at the end of the list
return sorted_list
Finally, a version that uses enumerate to get the indices and items in sorted_list rather than a simple range loop.
def insertion_sort(mylist):
sorted_list = []
for u in mylist:
for j, v in enumerate(sorted_list):
if v > u:
sorted_list[j:j] = [u]
break
else: #if you can't find a place in the list
sorted_list.append(u) #put number at the end of the list
return sorted_list
As often, it was a off-by-one error, the code below is fixed. I also made some parts a bit prettier.
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
for index, j in enumerate(sorted_list):
if j > i:
sorted_list.insert(index, i) #put the number in before element 'j'
break
else:
sorted_list.append(i) #put number at the end of the list
return sorted_list

I have to "write a program that adds all numbers from 2 to 10,000 to a list

I have to "write a program that adds all numbers from 2 to 10,000 to a list. Then remove the multiples of 2 (but not 2), multiples of 3 (but not 3), and so on, up to the multiples of 100. Print the remaining values." This is what I have so far down below, and I keep getting an error?
list = []
for i in range(2, 101):
list.append(int(i))
lenList = len(list)
print(lenList)
for i in range(lenList):
for j in range(2, 101):
if lenList[i] != j and lenList[i] % j == 0:
sum =0
for element in list:
print(element)
if lenList[i] != j and lenList[i] % j == 0: TypeError: 'int' object is
not subscriptable
lenList is not a list - it's the length of the list as defined in the line:
lenList = len(list)
You probably meant to write
if list[i] != j and list[i] % j == 0:

differences in for loops in python

can someone explain why these two loops look like they do the same thing, when in fact the second version doesn't find the duplicate number correctly?
list1 = [1,2,13,4,6,6,8,11,10]
for i in range(len(list1)):
for j in range(i+1, len(list1)):
if list1[i] == list1[j]:
print i, j
print True
else:
print False
print "--------------------------------------"
for i in list1:
for j in list1:
if i == j + 1:
print True, i, j
else:
print False
for i in range(len(list1)):
for j in range(i+1, len(list1)):
if list1[i] == list1[j]:
print i, j
print True
else:
print False
The code above iterates over a list which is generated by the range() function which returns a list of numbers that in your case is [0,1,2,....,len(list1) - 1] in the first loop.In the second loop the list that you go over is [i + 1, i + 2, i + 3,...,len(list1) - 1]. On every iteration i and jare assigned to one item of the list just like a normal for loop (Java, C#, C++ and more).
for i in list1:
for j in list1:
if i == j + 1:
print True, i, j
else:
print False
In this code i and j are assigned to each item value in list1.
On every iteration i and j will be assigned to the next item value in the list, NOT THE POSITION.
In your case i value will be 1 then 2 then 13... Same applies to j.
They don't do the same thing at all. The second one loops through the whole of list1 in the inner loop, instead of just from the current index onwards. And, for some reason, you add 1 to the value before comparing, so it wouldn't be equal.

Categories

Resources