Error: Too many values unpack (expected 2) when trying to loop - python

I'm trying to find a pair that is equal to 10 but cannot find it.
listOfIntegers = [8, 7, 2, 5, 3, 1]
target = 10
noOfpairs = 0
def findPair(listOfIntegers, target):
for i,j in range (len(listOfIntegers)),(len(listOfIntegers)):
if listOfIntegers[i] + listOfIntegers[j+1] == target:
print(listOfIntegers[i], "and", listOfIntegers[j], "is a pair")
noOfpairs += 1
print("number of pairs : ",noOfpairs)
break
print(findPair(listOfIntegers, target))

I don't know what your expected behaviour is, based on the way your code is written I assume you want to find the first pair and break...? But then why are you printing "number of pairs" if you break at the first pair...?
I'm going to assume you want to find the total number of consecutive pairs in a list that add to 10.
Your code, and where it's wrong:
noOfpairs is defined outside function findPair, but used inside.
Your for loop brackets are wrong - this is where you are getting your error.
You're breaking after finding the first pair (which might be what you want but it doesn't look like it)
You're running print("number of pairs : ", noOfpairs) inside the for loop (it's not a syntactical error but an inaccuracy - again, I don't get your expected behaviour)
You're printing the function (print(findPair(listOfIntegers, target))) as if it returned a value - it does not have a return statement therefore returns None. Run the function like this: findPair(listOfIntegers, target) or make it return noOfpairs.
In your for loop, why do you have 2 values i and j that both represent the exact same value for every iteration? It's not syntactically wrong but it makes no sense.
Correct code:
listOfIntegers = [8, 2, 5, 5, 1]
value_wanted = 10
def findPair(int_list, target):
noOfpairs = 0
for i in range(len(int_list) - 1): # To stop index out of bounds error
if int_list[i] + int_list[i + 1] == target:
print(int_list[i], "and", int_list[i + 1], "is a pair")
noOfpairs += 1
print("number of pairs : ", noOfpairs)
findPair(listOfIntegers, value_wanted)

Passing two arguments to range does not return a list of pairs - the first argument in that case is interpreted as the number to start the range from. Example:
print(list(range(3)))
print(list(range(1, 3)))
Output:
[0, 1, 2]
[1, 2]
For this task, a while loop is the simplest solution:
listOfIntegers = [8, 7, 2, 5, 3, 1]
target = 10
noOfpairs = 0
def findPair(iterable, pairSum):
i = 0
while i < len(iterable):
j = i + 1
if listOfIntegers[i] + listOfIntegers[j] == target:
print(listOfIntegers[i], "and", listOfIntegers[j], "is a pair")
noOfpairs += 1
print("number of pairs:", noOfpairs)
break
findPair(listOfIntegers, target)
Note how I changed the name of the arguments of the function - they should never be the same as the names of the variables passed to them, to avoid possible unexpected behaviour.

Related

How can I increment list items one by one and stop as soon as the sum of the list items has reached a target value?

I have a list of integers, and I want to add 1 to each integer in the list with every iteration of a while loop. More specifically, I want to perform this operation on the list's integers one by one (left to right) instead of all at once, and stop the loop as soon as the its conditional becomes False, even if that means stopping before the end of the list.
First, I tried the following:
def myfunction(someinput):
myintegerlist = [0, 0, 0]
while sum(myintegerlist) < someinput:
myintegerlist[0:] = [x+1 for x in myintegerlist[0:]]
return myintegerlist, sum(myintegerlist)
This doesn't do what I want, because it simultaneously adds 1 to all integers in the list. Thus if someinput = 4, it returns 6 as the sum and [2, 2, 2] as the list, whereas I would like it to stop at [2, 1, 1] before exceeding the input number. So I tried
while sum(myintegerlist) < someinput:
myintegerlist[indexplace] = [x+1 for x in myintegerlist[indexplace]]
indexplace += 1
This was just a guess, and throws "TypeError: 'int' object is not iterable". But I am stuck on how to get through the list items one by one and add 1 to them. Is there a good way to move incrementally through the list with each iteration? Or should I be trying something completely different?
Keep track of the index where you need to add the 1 during the while loop:
def myfunction(someinput):
myintegerlist = [0, 0, 0]
increment_index = 0 # next place to add 1
while sum(myintegerlist) < someinput:
myintegerlist[increment_index % len(myintegerlist)] += 1 # add 1 to the element, modulo length of the list to keep the index in range
increment_index += 1
return myintegerlist, sum(myintegerlist)
print(myfunction(4))
Result:
([2, 1, 1], 4)
Normally, in order to iterate over the values in a list you would just use
for value in myintegerlist:
# ...
but this doesn't allow you to directly change the value in the list.
You have to create a loop over the indices of the list.
for i in range(len(myintegerlist)):
value = myintegerlist[i]
In particular, by assigning to myintegerlist[i] you can change the values in the list.
for i in range(len(myintegerlist)):
value = myintegerlist[i]
myintegerlist[i] = new_value
Now you need one additional step, because you don't just want to iterate over each list index once, but possibly many times, until a condition is met. In order to keep the iteration going, you can use the cycle function from the itertools module.
from itertools import cycle
for i in cycle(range(len(myintegerlist))):
# i = 0, 1, 2, 0, 1, 2, 0, 1, ...
Now you can just add 1 to the value at the current list index and break the loop if the sum of the values has reached the desired amount:
for i in cycle(range(len(myintegerlist))):
if sum(myintegerlist) >= someinput:
break
myintegerlist[i] += 1
It is bad idea to start every time from 0. Too much meaningless iterations if someinput is a large number.
def get_els(sum_value: int, num_of_els: int = 3) -> tuple:
_list = [int(sum_value / num_of_els)] * num_of_els
if sum(_list) == sum_value:
return _list, sum_value
while True:
for idx in range(0, num_of_els):
_list[idx] += 1
if sum(_list) == sum_value:
return _list, sum_value
print(get_els(2))
print(get_els(4))
print(get_els(5))
print(get_els(10))
print(get_els(20))
Output:
([1, 1, 0], 2)
([2, 1, 1], 4)
([2, 2, 1], 5)
([4, 3, 3], 10)
([7, 7, 6], 20)
More over, if length of list is only 3 elements then loop is not necessary at all:
def get_els(sum_value: int) -> tuple:
_list = [int(sum_value / 3)] * 3
if sum_value % 3 == 0:
return _list, sum_value
if sum_value % 3 > 1:
_list[0] += 1
_list[1] += 1
else:
_list[0] += 1
return _list, sum_value

Why does the code give me wrong output for an amount? (Change making problem)

I was trying to solve the coin change problem in which we have to find the minimum number of coins that add up to a specific amount.
Here is the solution I came up with:
import sys
denomination = [1,6,10]
amount = 12
def coin_change(amount,denomination):
coins = 0
ans = [0]*(amount+1)
temp = sys.maxsize
for i in range(len(ans)):
for j in range(len(denomination)):
if denomination[j] <= i:
ans[i] = min(temp, ans[i-denomination[j]]) + 1
return ans
print(coin_change(amount,denomination))
The output is
[0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3].
Why is the last number in the output a 3 for the amount 12? I have gone through the code so many times, but I still don't understand why this happens. It gives 1 for the amount 6, so it should give 2 for the amount 12 instead of 3.
What's wrong with my code?
The problem is that min(temp, ...) is a useless call, as you never reduce the value of temp. This expression is always going to return the second argument. Obviously you really need to compare alternatives and choose the optimal one, so this is wrong.
And that is the reason you get 3. The last denomination that is tried is 10 (when j is 2). Before that try, ans[12] was actually 2, but it gets overwritten with 3 (10+1+1)!
Here is a correction:
import sys
denomination = [1,6,10]
amount = 12
def coin_change(amount,denomination):
ans = [sys.maxsize]*(amount+1) # initialise with maximum value
for i in range(len(ans)):
for j in range(len(denomination)):
if denomination[j] <= i:
if denomination[j] == i:
ans[i] = 1 # base case
else: # see if we can improve what we have
ans[i] = min(ans[i], ans[i-denomination[j]] + 1)
return ans
print(coin_change(amount,denomination))

How to rewrite a program to use recursion?

Just started to deal with recursion - I don’t understand everything in it yet. I think that i don't use a basic conditional, but i don't have any idea how to write it. The program itself works and execute everything i need, but there is no recursion.
The idea of the program is that there is a list in which is neede to sum of every x'th number in the list - x here as a step. If x = 0, then the sum is automatically zero. If x is out of range, then the sum is also 0
def sum_elements(nums, x) -> int::
if x not in range(-len(nums), len(nums)) or x == 0:
return 0
if x > 0:
nums = nums[x - 1::x]
return sum(nums)
return sum_elements(nums[::-1], -x)
if __name__ == '__main__':
print(sum_elements([], 0)) # x = 0 -> 0
print(sum_elements([1, 5, 2, 5, 9, 5], 3)) # 2 + 5 = 7
print(sum_elements([5, 6, 10, 20], -2)) # 10 + 5 = 15
print(sum_elements([5, 6, 10, 20], -20)) # x = -20 -> 0
Recursion is when a function calls itself and there a few (non-formal) rules that are always good to keep in the back of your mind when writing these:
1. The base case.
Every recursion function must have a base case that acts as essentially the end of the stack in the recursive call.
2. Every recursive function abides by the non-base(s) and the base case.
In other words, your code must be written in a way that the function either calls itself, or it terminates the recursive call. You can either do this by doing if and else statements, or only writing if statements to catch the base case(s).
3. The input of the function should keep in mind the state of the previous function.
In math, you might remember functions that call themselves (syntax switched for the case of explanation):
f(x)_(n=0) = f(x)_(n=1) + 10
which becomes:
f(x)_(n=1) = ( f(x)_(n=2) + 10 ) + 10
and so on. In essence, you are writing this with code and setting a base case that might say (for the example above, i.e.) "stop when n is 10". If that was the case, you should notice the cascading effect when we are layers deep into that function and when f(x)_(n=10) makes its appearance (and lets says returns 0 + 10) how we would have a final form of f(x)_(n=0) = 0 + 10 + 10 + 10 + ....
So for this function you instead have two inputs, nums and x. These inputs are what we will be modifying as we go down the recursion's stack.
1. Writing our base case.
Writing the base case is typically the easiest part of writing a recursion function. We know, for your problem, the following cases must be caught:
If x is not in the range of the length of nums, then we must return 0.
If len(nums) is 0, then we should return 0.
So lets begin:
def sum_elements(nums, x) -> int:
if len(nums) == 0 or not x in range(-len(nums), len(nums)):
return 0
Notice, however, that range(len([1, 2])) will return range(0, 2) but list(range(0, 2)) will return [0, 1]. Therefore, we must ensure to add a 1 to our len(nums) so that we can truly see if x is within the proper range:
def sum_elements(nums, x) -> int:
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
Notice that range(-len(nums), len(nums) + 1) for when nums = [1, 2, 3] is equals to range(-3, 4), but list(range(-3, 4)) is equals to [-3, -2, -1, 0, 1, 2, 3]. So therefore, we do not need a -len(nums) + 1 or -len(nums) - 1.
Once we have figured out the base case, we can start working on our actual function. At this point we have done #1 and a portion of #2, but we now must write our non-base(s) case(s).
2. Identifying our other-case(s):
As written in #2, our function input is what is dynamically changing as we go down our function stack. Therefore, we need to think about how we need to modify nums and/or x to fit our purposes. The first thing you should look at, however, is what would happen if we only change one of those variables as we go down the stack.
Keep nums constant, modify x: We know our base case ensures x stays within the constrain of the length of nums in both the positive and negative direction, which is good. However, we must increment x every time the function runs by the original x, or x_0. If we create the function and on every call say x + x, we are not adding the original x to itself, but rather adding the newer x's to itself. This is a problem. Take the following for example:
def sum_elements(nums, x) -> int:
print(nums, x)
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case. We must differentiate between positive x, and negative x.
if x > 0:
# Since x is an index that starts at 1, not 0, we must do x-1.
number = nums[x - 1]
else:
# For negative values of x this does not apply. [1, 2][-2] = 1
number = nums[x]
return number + sum_elements(nums, x + x)
Notice how we get:
# [NUMS] x
[1, 2, 3, 4, 5, 6] 2
[1, 2, 3, 4, 5, 6] 4
[1, 2, 3, 4, 5, 6] 8
# OUTPUT
6
and how the x value on the third call is 8. This is no bueno. The more you practice recursion, the more intuitive this concept will become on noticing how changing a certain input might not be the best. You ought to think: "what will this value be when the function continues down the stack?"
Keep x constant, modify nums: If we do this way we should be certain that we will not have issues with the value of x. The issue, then, becomes how we will modify the nums list and use x for our advantage. What we do know, is that x can be technically used as an index, as demonstrated above. So, therefore, what if instead of modifying the index, we modify the list in which that index takes from? Take the following for example:
nums = [1, 2, 3, 4]
x = 2
print(nums) # > [1, 2, 3, 4]
print(nums[x - 1]) # > 2
nums = nums[x:] # > [3, 4]
print(nums[x - 1]) # > 4
So it does seem like we can modify the list and keep a constant x to retrieve the information we want. Awesome! In such case #2 is the way to go.
3. Writing our other-case(s).
So now we will try to now write a function that keeps x constant, but modifies nums. We have a general idea from the code above, and we know from the previous point that we will have to deal with -x and x differently. Therefore, lets write something:
def sum_elements2(nums, x) -> int:
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case.
if x >= 0:
number = nums[x - 1]
nums = nums[x:]
else:
number = nums[x]
# Not sure what goes here.
return number + sum_elements(nums, x)
If we test the function above, it seems that it works for any positive x, but won't work for negative values of x. It makes sense, however, that whatever we do to the positive side, we must do the opposite to the negative side. If we try to use nums = nums[:x] we very quickly realize it works. Our final function becomes:
def sum_elements(nums, x) -> int:
# Base case.
if len(nums) == 0 or not x in range(-len(nums), len(nums) + 1):
return 0
# Other case.
if x >= 0:
number = nums[x - 1]
nums = nums[x:]
else:
number = nums[x]
nums = nums[:x]
return number + sum_elements(nums, x)
Running Examples
If we run examples with the above function, we get:
print(sum_elements([1, 2, 3, 4, 5, 6], 2)) # > 2 + 4 + 6 = 12
print(sum_elements([], 0)) # > 0
print(sum_elements([1, 5, 2, 5, 9, 5], 3)) # > 7
print(sum_elements([5, 6, 10, 20], -2)) # > 15
print(sum_elements([5, 6, 10, 20], -20)) # > 0
Maybe this approach can help you understand.
It starts from the first element and sums the rest every x ones.
That is my assumption, as you haven't provided an input and its desired output as an example.
In case you need to start from the xth element the code can be easily modified, I leave it to you to experiment with it.
def sum_elements(nums, x) -> int:
if x>0 and x<=len(nums):
return nums[0] + sum_elements(nums[x:], x)
return 0
lst = [1, 2, 3, 4, 5, 6]
print(sum_elements(lst, 2))
print(sum_elements(lst, 3))
print(sum_elements(lst, 0))
produces
9
5
0
Note: it just demonstrates recursion, but it's not optimal for a number of reasons.
Also it discards negative values of x

Summing the numbers in a list except for the first even number in Python?

i am tryin to write a function that sums all of the numbers except for the first even number on the list. a break function came into my mind for exiting the loop when encountered with the first even number but i couldn't managed to build it. i need help. thanks.
for example:
numbers = [4, 6, 7, 8, 9, 10]
totsum must be 6 + 7 + 8 + 9 + 10 = 40 (skipped the first even number '4')
here is my incomplete code:
nmbrs = [4, 6, 7, 8, 9, 10]
def totsum_effen(n):
#sum the total numbers except for the first even number
while True:
sum = 0
for i in nmbrs:
if i % 2 == 0:
break
sum = sum + i
return (sum)
I'd just sum it all and subtract the first even number (if it exists).
>>> numbers = [4, 6, 7, 8, 9, 10]
>>> sum(numbers) - next((x for x in numbers if x % 2 == 0), 0)
40
What you can do is just sum the array and subtract the first even number
nmbrs = [4, 6, 7, 8, 9, 10]
def totsum_effen(nmbrs):
#sum the total numbers except for the first even number
even_nmbrs = [num for num in nmbrs if num % 2 == 0]
temp_sum = sum(nmbrs)
if len(even_nmbrs) > 0:
temp_sum -= even_nmbrs[0]
return temp_sum
Try this;
nmbrs = [4, 6, 7, 8, 9, 10]
def totsum_effem():
nmbrs_copy = nmbrs.copy()
for index, num in enumerate(nmbrs):
if num % 2 == 0:
del nmbrs_copy[index]
break
return sum(nmbrs_copy)
>>> print(totsum_effem())
40
Here's another pythonic one liner (python3.x only):
In [36]: sum(num) - next(filter(lambda x: not x % 2, num + [0]))
Out[36]: 40
Your code will fail to add the odd numbers before the first even number.
This way you can keep a check and as soon as the first even number occurs skip that and continue with the loop.
def totsum_effen(nmbrs):
flag = 0
sum = 0
for i in nmbrs:
if flag == 0 and i % 2 == 0:
flag = 1
else:
sum += i
return sum
Firstly, instead of using break, you can try using continue. It simply skips the rest of the code in the loop for the current iteration and jumps to the next iteration.
Secondly, use a count variable to check for the first even number in the list.
Please check the following code. It's just an implementation of the things mentioned above.
nmbrs = [4, 6, 7, 8, 9, 10]
def totsum_effen(nmbrs) :
sum = 0
count = 0
for i in nmbrs :
if i%2==0 and count==0 :
count = count + 1
continue
sum = sum + i
return sum
print('Printing the sum of all the numbers in the list except the 1st even number....')
print(totsum_effen(nmbrs))
What you want to achieve can be done more efficiently with more complex code but that requires a deep understanding of Python. I re-write your code in beginner easy to understand Python with explanations for a few mistakes in your code and few things to pay attention to. Let me know if you can understand it.
#sum the total numbers except for the first even number (1)
def totsum_effen(n): #(2)
sum = 0 #(3)
ignore_first_even = True #(4)
for i in n:
if(i % 2 == 0 and ignore_first_even): #(5)
ignore_first_even = False
continue
sum = sum + i
return (sum)
print(totsum_effen(nmbrs))
you should place description of your function the line before the function definition block
In your code you the parameter n was never used. pass in parameter(s) you want to use in the function and refer to those parameters.
Usually, you want to declare your variable use for cumulation or totaling oustide of for loop or while loop. so it does not get reset every loop.
use a flat ignore_first_even to ignore the first even number by using ignore_first_even in an if statment in 4
if the number is even and the ignore_first_even is true then we set the ignore_first_even to false. Notice that ignore_first_even can never be set to true again this way we only ignore the first even number. Then we continue to the next iteration without adding this number to our sum
def totsum_effen(n):
#sum the total numbers except for the first even number
sum = 0
flag = False
for val in nmbrs:
if not flag:
if val % 2 == 0:
flag = True
else:
sum += val
else:
sum = sum + val
return (sum)
nmbrs = [4, 6, 7, 8, 9, 10]

adding sequential values in list to target value

The idea is for each number to add the next sequential numbers to try to reach the target value. If for each starting value (for i...) if adding the next sequential numbers exceeds the target then i has failed and move onto the next.
I'm getting some values slipping through and some duplicating.
If the targets intentionally match the lists it works fine; I've noticed 13 throws up some strange behaviour.
def addToTarget (mylist, target):
solutions_list = []
for i in range(0,len(mylist)):
#set base values
total = mylist[i]
counter = i
solutions = []
solutions.append(total)
if total == target:
solutions_list.append(solutions) # first value matches immediately
elif total > target:
solutions_list.append([counter-1, "first value already too high"])
elif counter == (len(mylist)):
solutions_list.append("caught as final value ")
while total < target and counter < (len(mylist)-1):
counter +=1
value = mylist[counter]
total += value
solutions.append(value)
if total == target:
solutions_list.append([counter, solutions])
elif total > target:
solutions_list.append([counter-1, "total > target during"])
elif counter == (len(mylist)-1):
solutions_list.append([counter-1, "total < target - came to end of list "])
else : solutions_list.append([counter-1, "not sure but certian values seem to slip through"])
return solutions_list
mylist = [5, 5, 3, 10, 2, 8, 10]
solutions_list = []
test = answer(mylist, 13)
for i in test : print(i)
You could use two markers that move through the list and keep track of sum of values between them. While current sum is less than target (13) and first marker is not at the end of the list move it forward and add value to current sum. Once first marker has been moved check if the current sum matches the target and update result accordingly. In final step move second marker forward one step and subtract item that it pointed to from current sum.
l = [5, 5, 3, 10, 2, 8, 10]
TARGET = 13
res = []
end = 0
current = 0
for start in range(len(l)):
while current < TARGET and end < len(l):
current += l[end]
end += 1
res.append(l[start:end] if current == TARGET else 'fail')
current -= l[start]
print(res)
Output:
[[5, 5, 3], 'fail', [3, 10], 'fail', 'fail', 'fail', 'fail']
Your code and your problem statement would benefit from rewriting as a sequence of small, self-contained, painfully obvious steps.
As far as I could understand, you take a list of numbers xs and look for values of i such that xs[i] + xs[i + 1] == target.
So, let's first generate a list of triples (i, x[i], x[i + 1]), then scan it for solutions.
An explicit way:
def pairs(xs):
for i in range(len(xs) - 1):
yield (i, xs[i], xs[i + 1])
A one-line way, fine for reasonably short lists:
def pairs(xs):
return zip(range(len(xs)), xs, xs[1:])
Now find the matches:
matches = [(i, x0, x1) for (i, x0, x1) if x0 + x1 == target]
We don't mark the various conditions of mismatches, though. Tese can be added if the list comprehension above is converted into an explicit loop.
Hope this helps.

Categories