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
Related
I am doing python exercise and I can not finish it. I need to a create array and fill it 25 numbers, every number will be the sum of previous one and the value drawn from the set (-5, 5).
import numpy as np
import random
def prog_list(mylist):
mylist = [0]
addlist = [-5,5]
sum_list = 0
for i in mylist:
if len(mylist) < 25:
sum_list = random.choice(addlist) + mylist[i-1]
mylist.append(sum_list)
else:
return mylist
for x in prog_list(mylist):
print(x)
When I print x I've got
IndexError: list index out of range
this works:
def prog_list(n):
mylist = [0]
#addlist = [-5,5]
addlist = list(range(-5, 5+1))
for i in range(1, n):
_sum = random.choice(addlist) + mylist[i-1]
mylist.append(_sum)
return mylist
prog_list(25)
if you want to draw any integer from (-5, 5) you need this:
addlist = list(range(-5, 5+1))
there is an even cleaner way to do it where you dont acces the list in every iteration:
def prog_list(n):
mylist = []
_sum = 0
#addlist = [-5,5]
addlist = list(range(-5, 5+1))
for i in range(n):
mylist.append(_sum)
_sum += random.choice(addlist)
return mylist
prog_list(25)
for i in mylist:
if len(mylist) < 100:
sum_list = random.choice(addlist) + mylist[i-1]
mylist.append(sum_list)
else:
return mylist
This construct will get value of element of mylist as i. First element is 0 so you get one of {-5,5} + mylist[-1] ([-1] means last element in python language), this result in either -5 or 5, then you get that value less 1 which is either -6 or 4, but there is not enough elements to get -6 (i.e. 6 from right) or 4 (i.e. 5 from left) element, thus IndexError. To avoid that you might replace your for using following while
while len(mylist) < 100:
sum_list = random.choice(addlist) + mylist[-1]
mylist.append(sum_list)
return mylist
for i in mylist
iterates over the items in your list, so on the first step when you add or subtract 5, you will be trying to access the (5 - 1)th or the (-5 - 1)th element with mylist[i - 1], and that will give you an IndexError.
To get the current last element of your mylist, you should use
mylist[-1] instead of mylist[i - 1]
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:
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.
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)
This code should print the sum of the even numbers in the first ten numbers of the Fibonacci sequence.
#Creates a list with the first ten Fibonacci numbers.
l = [1,2]
for i in range(10):
l.append(l[i]+l[i+1])
for i in l:
#If an element of the Fibonacci list is uneven, replace it with zero.
if l[i]%2 != 0:
l[i] = 0
#Print the sum of the list with all even Fibonacci numbers.
print sum(l)
When I execute this I get:
File "pe2m.py", line 6, in <module>
if l[i]%2 != 0:
IndexError: list index out of range
I don't get how its going out of range, could someone clarify?
Your problem is for i in l: it doesn't give you the indices, it gives you the list elements. As the elements are integers, they could be valid (and the first few will be) but they don't have the values you want -- you'll have to iterate over a range again.
You are looping over the values not the index positions!
Use the following code instead:
#Creates a list with the first ten Fibonacci numbers.
l = [1,2]
for i in range(10):
l.append(l[i]+l[i+1])
for i in range(len(l)):
#If an element of the Fibonacci list is uneven, replace it with zero.
if l[i]%2 != 0:
l[i] = 0
#Print the sum of the list with all even Fibonacci numbers.
print sum(l)
You cannot index a list with the value from the list as it is not guaranteed that the value will be within the list boundary
Seeing your code, I feel you are planning to do something as below
>>> for i,e in enumerate(l):
#If an element of the Fibonacci list is uneven, replace it with zero.
if e%2 != 0:
l[i] = 0
Interestingly you can do the same as below. (Edited after seeing glglgl's comment]
>>> print sum(e for e in l if e%2)
Python's for x in y construct returns the values/elements of a sequence in x, not their index.
As for the Fibonacci numbers: The sequence starts with 1, 1 and not 1, 2. And the sum can be done simpler like this:
a, b = 1, 1
s = 0
for i in range(10):
a, b = b, a+b
if b % 2 = 0:
s += b
print s
If you need to get the sum of the first N even numbers, you would do:
a, b = 1, 1
s = 0
count = 0
while count < 10:
a, b = b, a+b
if b % 2 = 0:
s += b
count += 1
print s
And just for fun the version with generators in a functional style:
from itertools import islice
def fib():
a, b = 1, 1
yield a
yield b
while True:
a, b = b, a+b
yield b
even_sum = reduce(lambda x, y: x+y if y % 2 == 0 else x, islice(fib(), 10), 0)