IndexError: list index out of range in while loop - python

I cant get to understand why i`m getting Index Error.
at a = array1[item]
while item <= n:
a = array1[item]
t = mid - a
l = h_f(t)
ab += l
if ab > k:
item+=1
break
ae += h_f(t + 1) - 1
item+=1
n - number of inputed values, item = 0
array1 = [2, 3, 4]
Any help?

An list with n elements has items in indexes 0 through n-1. I.e., your loop should stop before n, not at it. Replace <= with < and you should be OK:
while item < n:
# Here -^

Arrays start indexing from 0 so last index is 2.
While n can be 3 code can get out of bounds
while item < n:

Related

Loop gets stuck on the third index

Good day. I need to make a function that returns a sum of the two lowest positive integers in the list.
It didn't work out so I've made it print its each step and then I saw that it gets stuck on the third index for some reason. It says 'list index out of range' but I can't quite understand why is it if there are 5 positions in the list. Can't figute it out on my own.
def sum_two_smallest_numbers(numbers):
a = 2147483647
numers = numbers
b = a
for i in range(0, len(numbers)):
print(numbers[i])
if numbers[i] < a and numbers[i] > 0:
a = numbers[i]
numbers.pop(i)
for j in range(0, len(numers)):
if numers[j] < b and numers[j] > 0:
b = numers[j]
numers.pop(j)
return a + b
print(sum_two_smallest_numbers([19, 5, 42, 2, 77]))
This works.
a = [-1, 2, 34, 22, 4]
a = [i for i in a if i > 0]
first_min = min(a)
a.remove(first_min)
second_min = min(a)
print(first_min+second_min)
pop removes a value from the list so each time you use pop the length of your list gets shorter and right now you keep deleting numbers from your list using this algorithm.
def sum_two_smallest_numbers(numbers):
a = 2147483647
numers = numbers
b = a
ind = -1
for i in range(0, len(numbers)):
# print(numbers[i])
if numbers[i] < a and numbers[i] > 0:
a = numbers[i]
ind = i
numbers.pop(ind)
for j in range(0, len(numbers)-1):
if numers[j] < b and numers[j] > 0:
b = numers[j]
return a + b
print(sum_two_smallest_numbers([19, 5, 42, 2, 77]))
Note that this algorithm assumes there are at least 2 positive numbers in your list. Also, there are more efficient ways to do this with only one for loop.
First the rule is never modify a list while iterating on it. You are trying to circumvent it by using indices, but you compute the range before starting the loop and then remove elements from the list => at a time you get an index that is greater or equal than the size of the list.
In addition, you will remove more elements than the smallest one. Let us assume that we fixed the above error and see what happens
first iteration: 19 is less than 2147483647: a = 19 and 19 is removed from the list
next: 5 is less that 19: again a = 5 and 5 is removed which is bad because it is the second smallest element !
So you should at least change your algo to only remove the final smallest element:
def sum_two_smallest_numbers(numbers):
a = 2147483647
numers = numbers
b = a
for i in range(0, len(numbers)):
print(numbers[i])
if numbers[i] < a and numbers[i] > 0:
a = numbers[i]
numbers.remove(a)
for j in range(0, len(numers)):
if numers[j] < b and numers[j] > 0:
b = numers[j]
numers.remove(b)
return a + b
print(sum_two_smallest_numbers([19, 5, 42, 2, 77]))
But this is un-pythonic because Python lists are iterable, and not efficient because you iterate the array twice. This would be better:
def sum_two_smallest_numbers(numbers):
a = b = 2147483647 # a and b will be the 2 smallest elements
for i in numbers:
print(i)
if i < b: # if i >= b : nothing to do
if i < a: # new element is the current smallest
b = a
a = i
else: # new element is the current second smallest
b = i
# uncomment both following line if you want to remove the elements from the array
# as a side effect
# numbers.remove(a)
# numbers.remove(b)
return a + b

How to check if any item exists in the list

How to check whether a list and an element of a list with such an index exist in the list itself?
I have a list [[10,10,9], [10,10,10], [10,10,10]]
Then I enter the number of coordinates (k) and the coordinates themselves. At these coordinates, I have to subtract 8 from the cell and 4 with each cell standing next to it. But what if there are no cells nearby?
When checking if field [r + f] [c + s] in field: it always gives a negative answer. How to make a check?
for i in range(k):
for j in range(1):
f = drops[i][j]
s = drops[i][j + 1]
field[f][s] -= 8
for r in range(-1, 1):
for c in range(-1, 1):
if not (r == c == 1):
if field[r + f][c + s] in field:
field[r + f][c + s] -= 4
You just have to check whether the index isn't at the start or the end of the list.
n = 2
mylist = [4, 5, 8, 9, 12]
if len(mylist) > n+1:
mylist[n+1] -= 1
if n > 0:
mylist[n-1] -= 1
Slice assignment might help. You have to avoid letting an index go negative, but something like
s = slice(max(n-1,0), n+2)
x[s] = [v-1 for v in x[s]]
isn't too repetitive, while handling the edge cases n == 0 and n == len(s) - 1. (It won't work ifn` is explicitly set to a negative index, though.)

IndexError: list index out of range when using variabel to indexing

def adjacentElementsProduct(inputArray):
i = 0
n = []
t = int(0)
b = int(1)
while i < len(inputArray):
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
return n
print(adjacentElementsProduct([3, 6, -2, -5, 7, 3]))
Can some one help me when I try to execute this its return
IndexError: list index out of range
Sorry for my bad English Grammar
You need to change your loop so that i only iterates up to len(inputArray) - 1.
Like this:
def adjacentElementsProduct(inputArray):
i = 0
n = []
t = 0
b = 1
while i < len(inputArray) - 1:
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
return n
print(adjacentElementsProduct([3, 6, -2, -5, 7, 3]))
This is because your noob array is essentially just each adjacent pair of elements in inputArray. Naturally, the number of pairs in a list of i elements is i - 1. This means that you need to change your loop to stop one iteration before, as it's throwing the IndexError when t is the len(inputArray) - 1 and b is the len(inputArray) (b isn't a valid value in the last iteration of your current code as there's not that many elements).
Here you set i=0, t=0, and b=1, thus your b always greater than i by 1. So, in the last loop (where t and i should equal len(inputArray) -1), the value of b should be len(inputArray) which is bigger than the length of your array.
I am not very sure about your excepted output, but I guess you could fix it like following:
while i < len(inputArray) - 1:
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
You can change the while loop for a for loop and use try / except to return the result when it reaches the end of the iteration. You can also add in extra except clauses to catch other errors and make use of else and finally if needs be .. https://docs.python.org/3/tutorial/errors.html
def adjacentElementsProduct(inputArray):
i = 0
n = []
t = int(0)
b = int(1)
for i in range(len(inputArray)):
try:
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
except IndexError:
return n
return n
print(adjacentElementsProduct([3, 6, -2, -5, 7, 3]))
l=[3, 6, -2, -5, 7, 3]
print([x*y for x,y in zip(l,l[1:])])
Here zip is used to create the adjacency pair

Subsetting python list into positive/negative movements/trends

Sorry for creating this question but I have been stuck on this question for a while.
Basically I'm trying to take a list:
numbers=[1, 2, -1, -2, 4, 5]
And subset this list into a list of list that display positive/negative movements (or trends)
The end result is to have:
subset_list = [[1, 2], [-1, -2], [4, 5]]
Basically I have been using nested while functions to append a positive movement to the subset, and when the condition is not met, the subset is appended to subset_list and then evaluates if there is a negative movement.
I keep getting an IndexError, and so far subset_list only contains [[1, 2]]
Here is my code:
numbers = [1,2,-1,-2,4,5]
subset = []
subset_list = []
subset.append(numbers[0])
i = 1
while i < (len(numbers)):
if numbers[i] <= numbers[i+1]:
subset.append(numbers[i])
i+= 1
while subset[-1] <= numbers[i] or numbers[i] <= numbers[i+1]:
subset.append(numbers[i])
i += 1
subset_list.append(subset)
subset = []
i += 1
if numbers[i] > numbers[i+1]:
subset.append(numbers[i])
i+= 1
while subset[-1] <= numbers[i] or numbers[i] <= numbers[i+1]:
subset.append(numbers[i])
i+= 1
subset_list.append(subset)
subset = []
i += 1
Thanks!
-Jake
Here is a way to re-write this:
numbers=[1,2,-1,-2,4,5]
direction = True # positive or negative
prevdirection = True
res = [[numbers[0]]]
for previtem, item in zip(numbers[:-1], numbers[1:]):
direction = True if item - previtem > 0 else False
if direction != prevdirection:
res.append([])
prevdirection = direction
res[-1].append(item)
print(res)
In python, one tends not to use the actual indexes in a list very often. Try a for-loop instead, plus a check to see whether the trend changed or not (this treats zero as a distinct trend from positive or negative - you can pretty simply change same_direction to group it one way or the other):
def same_direction(num1, num2):
# both numbers are positive, both are negative, or both are zero
return ((num1 > 0 and num2 > 0) or
(num1 < 0 and num2 < 0) or
(num1 == num2))
numbers = [1, 2, -1, -2, 4, 5]
result = [[]] #list with one sublist ready
last_number = 0
for num in numbers:
if same_direction(num, last_direction):
# No need for a new sublist, put new number in last sublist
result[-1].append(num)
else:
# trend changed, new sublist and put the number in it
result.append([num])
If change in trends always go through the sign change, you can "group" items based on a sign using itertools.groupby():
>>> from itertools import groupby
>>>
>>> [list(v) for _, v in groupby(numbers, lambda x: x < 0)]
[[1, 2], [-1, -2], [4, 5]]
We are using _ as a variable name for a "throw-away" variable since we don't need the grouping key in this case.
This is what I came up with. It is close to what you have but a little easier to read. I avoid having to increment the index counter i as much which is probably where you went wrong.
n= [1,2,-1,-2,4,5]
out=[]
i=1
tmp=[n[0]]
while i < len(n):
if n[i] >= 0 and tmp[-1] >= 0:
tmp.append(n[i])
elif n[i] < 0 and tmp[-1] < 0:
tmp.append(n[i])
else:
out.append(tmp)
tmp = [n[i]]
i = i + 1
if len(tmp) > 0: # typo fix was > 1
out.append(tmp)
print(out)
Here is my solution:
numbers = [1,2,-1,-2,4,5, 3, 2]
subset = []
subset_list = []
subset.append(numbers[0])
forward = 1
for i in range(0, len(numbers) - 1):
if ( forward == 1 ):
if numbers[i] <= numbers[i+1]:
subset.append(numbers[i+1])
else:
subset_list.append(subset)
subset = []
subset.append(numbers[i+1])
forward = 0
else:
if numbers[i] >= numbers[i+1]:
subset.append(numbers[i+1])
else:
subset_list.append(subset)
subset = []
subset.append(numbers[i+1])
forward = 1
subset_list.append(subset)
print(*subset)
print(*subset_list)
Unfortunately, I only have python 3 on my system so my answer is in python 3.

Competition practise task (Python)

Not sure if it's the best title. The explanation of what the program is suposed to do is below, my version only works with the first example but it doesn't work in the second when you get for example 1 1 3 1 1 2 because i can't figure out a good way to handle so much variations especially if K is bigger than 3 and the limit is 50. My version:
N, K, M = map(int, input().split())
niz = list(map(int, input().split()))
nizk = list(range(1, K+1))
izlazi = []
for r in range(0, M):
operacija = list(map(int, input().split()))
index = 0
if operacija[0] == 2:
nizkk = []
for z in range(0, len(nizk)):
if nizk[z] in niz:
continue
else:
izlazi.append(-1)
break
for p in range(0, N):
if niz[p] not in nizkk:
nizkk.append(niz[p])
nizkk.sort()
if nizkk == nizk:
index = p
izlazi.append(index+1)
break
else:
continue
else:
index, repl = map(int, operacija[1:])
niz[index - 1] = repl
print(izlazi)
In the first line of the input there should be N, K, M (1 <= N, M <= 100k, 1 <= K <= 50, you don't need to actually check this the numbers that are tested will always be in those ranges). In the second line of input you put a list of numbers which are the lenght of N you entered earlier. M is the number of operations you will do in the following lines of input. There can be 2 operations. If you enter 1 p v(p = index of number you want to replace, v the number you replace it with) or if you enter 2 it needs to find the shortest array of numbers defined by range(1, K+1) in the list of numbers you entered in line 2 and possibly changed with operation 1. If it doesn't exist it should output -1 if it does it should output lenght of numbers in the array you look in(numbers can be like 2, 1, 3 if you're looking for 1, 2, 3, also if you're looking for 1, 2, 3 etc and you have 2, 1, 1, 3 as the shortest one that is the solution and it's lenght is 4). Also the replacement operation doesnt count from 0 but from 1. So watch out when managing lists.
These are the examples you can input in the program ulaz = input, izlaz = ouput:
I have the following idea:
Min length sequence either starts from first element or does not contain first element and hence equals to min length of the same sequence without first element.
So we have recursion here.
For sequence [1,1,3,2,1,1] and [1,2,3] we will have:
Min length from start element [1,1,3,2,1,1] is 4
Min length from start element __[1,3,2,1,1] is 3
Min length from start element ____[3,2,1,1] is 3
Min length from start element ______[2,1,1] is -1
Can stop here.
Result is minimum for [4,3,3] = 3
You have already implemented the part for min length, if it starts from the first element. Need now extract it as a function and create a recursive function.
Some metacode:
function GetMinLength(seq)
{
minLengthFromFirstElement = GetMinLenthFromFirstElement(seq)
minLengthFromRest = GetMinLength(seq[1:]) //recusive call
return Min(minLengthFromFirstElement, minLengthFromRest )//-1 results should not count, add extra code to handle it
}
Unfortunately I don't know python, but I can provide code on F# in case you need it.
EDIT:
Try this:
N, K, M = map(int, input().split())
niz = list(map(int, input().split()))
nizk = list(range(1, K+1))
izlazi = []
def GetMinLengthStartingFromFirstElement(seq):
nizkk = []
for z in range(0, len(seq)):
if seq[z] in nizk:
continue
else:
return -1
for p in range(0, len(seq)):
if seq[p] not in nizkk:
nizkk.append(seq[p])
nizkk.sort()
if nizkk == nizk:
index = p
return index+1
else:
continue
return -1
def GetMinLength(seq):
if len(seq) == 0:
return -1
else:
curMinLength = GetMinLengthStartingFromFirstElement(seq)
if curMinLength == -1:
return -1
minLengthFromRest = GetMinLength(seq[1:])
if minLengthFromRest > -1:
return min(curMinLength,minLengthFromRest)
else:
return curMinLength;
for r in range(0, M):
operacija = list(map(int, input().split()))
index = 0
if operacija[0] == 2:
minLength = GetMinLength(niz)
izlazi.append(minLength)
else:
index, repl = map(int, operacija[1:])
niz[index - 1] = repl
print(izlazi)

Categories