Finding a pair of values which add up to given sum - python

lst = [3, 4, 1, 2, 9]
givenSum = 12
table = {}
x = 0
y = 0
for i in range(0, len(lst)):
table[givenSum - lst[i]] = 1
i += 1
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
break
This is the output
9 and 3 is equal to 12
3 and 9 is equal to 12
I don't know why it's being shown up twice. I need to find a pair of values that add up to the given sum and this is the only way I could think of. I only want it to show up once though any ideas on how I can do that?

There are better solutions, but to fix your issue making minimal changes to your code:
lst = [3, 4, 1, 2, 9]
givenSum = 12
for x in range(0, len(lst) - 1):
for y in range(x + 1, len(lst)):
if lst[x] + lst[y] == givenSum:
print(lst[x], "and", lst[y], "is equal to", givenSum)
break
This will print
3 and 9 is equal to 12
Note that the redundant table is completely removed from the code.
If you run it for a better test case:
lst = [3, 4, 5, 6, 7, 1, 2, 9]
it will print
3 and 9 is equal to 12
5 and 7 is equal to 12

First, to address why the looping continues and gives a second output, break can only break out of its immediate loop. Since you have a nested loop, the break only stops the for y in table: inner loop, but allows for x in table outer loop to move onto it's next iteration. So eventually, x is able to take the value of 3 later on, thus giving you the two outputs you see.
So, if you need a way to stop the iteration entirely when a solution is found, you need to either chain the break statements using a for else syntax (which arguably might be tough to read) as follows,
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
break #breaks from inner loop
else: #for else syntax: this block runs if and only if there was no break encountered during looping.
continue #jumps the outer loop to next iteration
break #this break is set at outer loop's level. Essentially, we can only reach this portion if there is a break in the inner loop.
For else says: run through the whole iteration, and if no break is found, executes the code in the else block. Essentially, the "else" of a "for else" is like a "for - no break".
However, one easier alternative is to use a function with a return (which also makes it easier to read the code).
def find_given_sum(lst, givenSum):
table = {}
x = 0
y = 0
for i in range(0, len(lst)):
table[givenSum - lst[i]] = 1
i += 1
for x in table:
for y in table:
if (x + y) == givenSum:
print(x, "and", y, "is equal to", givenSum)
return #this returns immediately out of the function, thus stopping the iteration.
Also, you could just repeat the break condition, but repeating code is generally not a good practice.
Hope this helps address why the two outputs are being printed. Now, as for the solution itself, there's actually a much better way to solve this. It builds upon the idea of compliments, which you seem to have a sense of in your table. But it doesn't require iteration over the table itself. As a hint: the ideal solution runs in O(n) time. I will not discuss the ideal solution, but hope this prompts you to find the best approach.

Looping twice for n elements costs you O(N^2) time, which is inefficient for large lists. Modified and tested the code to use hash map/dictionary to store the list elements and now it will take only O(N) time.
Map = dict()
lst = [3, 4, 1, 2, 9]
givenSum = 12
for i in range(0, len(lst)):
rem=givenSum-lst[i]
if rem in Map:
print lst[i],lst[Map[rem]]
else:
Map[lst[i]]=i
Store the value of each list element into the map whenever it does not exist in the map.
At each iteration, take the difference between givenSum and current element at that iteration and then search for that difference in the Map.
If it exists it means the pair exists or else not.
In this approach you are running the loop only once, which takes O(N) time because accessing elements in hash map is O(1)/constant time.

Use itertools to get the result
import itertools
sum = 10
lst = [3, 4, 1, 2, 9]
ans = list(filter(lambda x : x[0]+x[1] == sum,itertools.combinations(lst, 2)))

Related

how to loop through each element in list and increment by one

Hello i want to ask how to loop through each element and increment every time by one this is what i want first i want to sum 0 , 1, 3 ,6 , 10 and after that sum can somebody help me about that i don't know how to tell if it is loop through each element or iterate.It should look like these examples.I am sorry!
ls = [0, 1, 3, 6, 10]
ls = [1, 3, 6, 10]
ls = [3, 6, 10]
ls = [6, 10]
ls = [10]
ls = []
Here's the problem who i want to solve it :
https://www.codewars.com/kata/5ce399e0047a45001c853c2b/train/python
I tried this but it doesn't work
def parts_sums(ls):
length_list = len(ls)
for i in range(0,length_list+1):
return length_list
Note that there is a built-in function sum() in Python that does that job probably better than any code you can write in Python.
sum([0, 1, 3, 6, 10])
However, if you want to practice writing your sum function by iterating through a list and summing all the elements, this is how you do it.
def my_sum(ls):
result = 0
for i in range(len(ls)):
result += ls[i]
return result
First of all, you need to initialize a variable to hold your result. The range() function generates all values from 0 to x. The for-loop assigns all values generated by the range function to i in order and executes the indented block below. The += assignment increments the left-hand side variable by the right-hand side expression value. At last, we return the result.
And if you prefer using a while-loop,
def my_sum(ls):
result = 0
i = 0
while i < len(ls):
result += ls[i]
i += 1
return result
It's always good to consult Python documentation when you are not sure how to use its built-in function.
If you want the accumulated sum of all items reversed, you can take a look at the accumulate function in itertools.
from itertools import accumulate
def parts_sums(ls):
return list(accumulate(ls[::-1]))[::-1] + [0]
Or if you want to implement with a loop,
def parts_sums(ls):
result = []
part_sum = 0
for item in ls[::-1]:
result.append(part_sum)
part_sum += item
result.append(part_sum)
return result[::-1]
Or if you want to do it without reversing the list (say if you want to yield the results)
def parts_sums(ls):
result = []
part_sum = sum(ls)
for item in ls:
result.append(part_sum)
part_sum -= item
result.append(part_sum)
return result
Note the algorithm is still O(n), not that time complexity matters in this case.
For the question you have mentioned in codewars, you need to loop it thro 2 loops and keep reducing the first element in the inner loop for sum.
def parts_sums(ls):
# your code
sum = []
for i in range(len(ls)):
sum_temp =0
for j in range(i,len(ls)):
sum_temp += ls[j]
sum.append(sum_temp)
sum.append(0) # for the final empty list
return sum
print(parts_sums([0, 1, 3, 6, 10]))
This test will check the execution time too. So you need to be fast.
Naive approach
You can use sum or create your own sum.
def parts_sums(ls):
return [
sum(ls[i:])
for i in range(len(ls) + 1)
]
But i means you'll need to loop in a list twice. So it will be slow.
Sneaky approach
In a list like [a, b, c, d, e] you are calculating:
[a+b+c+d+e, a+b+c+d, a+b+c, a+b, a, 0]. So let's start from last to first element. [0, a, a+b, a+b+c, a+b+c+d, a+b+c+d+e]. Now we see a cumulative iteration:
So get loop in the list, get the element, sum it with last element of the result ([0]) list and add it as the last element to the result list. Lastly reverse the result.
def parts_sums(ls):
res = [0]
for i in range(len(ls)-1, -1, -1):
res.append(res[-1] + ls[i])
return res[::-1]

Factorial list in python 3 not running

I'm still a beginner so please bear with me. So I'm trying to get a list of factorial numbers from 1 to 5.
factorial=[]
for i in range(1,5):
for x in range(1,5):
while(i>x):
factorial.append(i*x)
When I switch out the factorial.append for print it just continously spits out 2s, does anyone know why, and if so what to do to fix this and what other viable method is there to get a list of factorial numbers?
I this case, I recommend you to use a recursive function:
def factorial(x):
if x == 1:
return 1
else:
return x*factorial(x-1)
Ex:
>>>factorial(5)
120
>>>factorial(10)
3628800
you can do something like :
>>> f=[1] # initialized your list
>>> for i in range(5): # take each value in the list [0,1,2,3,4]
... f.append(f[i]*(i+1)) #to create a next point multiply with the last value
...
>>> f=f[1:] #don't keep the first (repeated) point
>>> f #you have your list !
[1, 2, 6, 24, 120]
You're getting stuck in your while loop.
If you go step by step through your code, you'll see what is going on:
In the first loop, i value will be 1, and x values from 1 to 5, so i will never be > than x, thus you won't enter the while loop.
At the start of the second loop, i value will be 2 and x value will be 1, so you will enter the while loop.
You will stay in stay in the while loop until i becomes lower or equal to x, but this will never happen because to continue with the for loop you'll need to exit the while loop first.
Despite the error, i do not understand the reasoning that brought you there.
The common way to handle factorials is with recursion, as #Julio CamPlaz's answer shows, but it may simplier to understand the following:
# in each for loop, you multiply your n variable for the i value
# and you store the result of the moltiplication in your n variable
n=1
for i in range(1,6): # if you want the numbers from 1 to 5, you have to increase by one your maximum value
n = n*i
print n

Counting down and then up

I'm new to python and trying to run a function that will, given one variable, count down to zero and then up to the original variable. the output should look something like this:
>>> functionname(5)
5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5
so far I've written the code below, but this doesn't count up all the way to the original variable. I guess I need to somehow save the variable in order to refer to it later, but I have no idea how to do that, since python automatically changes n as the function goes on.
def functionname(n):
n = orginal
while n > 0:
print n
n=n-1
print n
if n==0:
print n
n=n+1
I would be very grateful for some pointers, as I seem to be completely stuck at the moment.
Just count from negative to positive and use math:
def fn(n):
print ', '.join(str(abs(i)) for i in range(-n, n+1))
fn(5)
# 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5
Pointers:
If you already know the range you want to iterate over, it's much cleaner and more direct to use a for loop instead of a while.
You can use the range function to generate number sequences.
You can convert simple for loops into list-comprehensions as I did above.
The "simple" clean implementation of your requirements would look something like this:
def fn(n):
for i in range(n, 0, -1):
print i,
for i in range(n + 1):
print i,
Other notes:
range can count backwards too
The end argument to range isn't included in the range itself, that's why the second loop specifies n + 1 as the limit (instead of just n)
Adding a trailing comma on your print makes it add a space at the end instead of a line-break.
Your second block is an if n == 0: (which you know it is since the while loop terminated when n hit 0); presumably you want while n <= 5.
Note that there are nicer ways to accomplish the same thing in Python. For example, using a pair of ranges with itertools.chain to iterate each range one after another allows you to simplify to:
import itertools
def functionname(n):
for i in itertools.chain(range(n, 0, -1), range(n+1)):
print i
Personally, I'd do something like...
def count(n):
for x in range(n, -n, -1):
print(str(abs(x)) + ",")
At the suggestion of dlewin, here's a list comprehension of the same...
def count(n):
print(','.join(str(abs(x)) for x in range(n, -n, -1)))
You need a second while loop that starts at 0 and goes back up to "original".
Do you know about "for" loops yet? Those are better for counting.
Your idea about having original is correct however you are using the assignment operator the wrong way 'round. Also the if n==0 line should be another loop (while or for as suggested by other answers), counting back up to original.
So I'd start with copying the value from n to original like this:
original = n
Hope that helps!
You got some bad formatting there. Remember to indent properly for functions and while and if statements.
So first, set n to 5. Then count down from there until you reach 0 with a while loop:
while n != -1:
print n
n -= 1
Then after the loop breaks, count back up again and reset n to 0:
n = 0
while n < 6:
print n
n += 1

Python Method Returning None

I'm having a very odd problem. I wrote a method that determines the degree of a formula describing a set of numbers, when given the said set. The method is fairly simple, I've added in a couple of lines for debugging purposes:
def getdeg(numlist, cnt): #get the degree of the equation describing numlist
count = cnt #initial run should be with cnt as 0
templist = []
for i in range(len(numlist) - 1): #exclude the last item (which doesn't have an item after it)
templist.append(numlist[i+1] - numlist[i]) #append the val of index i+1 minus index i
count += 1
print(templist)
if not allEqual(templist):
print("Not all equal, iterating again")
getdeg(templist, count)
else:
print(count)
return count
def allEqual(numlist):
if len(numlist) == 1:
return True
for i in range(len(numlist) -1):
if not (numlist[i] == numlist[i+1]):
return False
return True
Now, I'm running this on a set of numbers I KNOW to be described by a 3rd-degree equation, like so:
x = getdeg([2, 8, 9, 11, 20], 0)
print(x)
Fairly simple, yes? Except when you run this, it prints out the following:
[6, 1, 2, 9]
Not all equal, iterating again
[-5, 1, 7]
Not all equal, iterating again
[6, 6]
3
None
Everything is looking good, right up until that "None." What is it doing there? I would assume that the else conditional isn't being executed, but it's printing out 3 just fine, so it obviously is. That also means that the program "knows" what the value of count is, but it's not returning it right. Could someone enlighten me as to what on earth is going on?
if not allEqual(templist):
print("Not all equal, iterating again")
getdeg(templist, count)
Remember, when a method recursively calls itself, you still need to explicitly return the value if you want a value to be returned.
if not allEqual(templist):
print("Not all equal, iterating again")
return getdeg(templist, count)
You need to return a value in the if clause as well.
return getdeg(templist, count)

While in a for loop

I want to know the number of zeros which first appear in a list, before any other number.
For example:
L1 = [0, 0, 0, 0, 0, 1, 2] - the output should be 5, which is the number of zeros.
L2 = [1, 0, 0, 0, 0, 0, 2] - the output should be zero. Although there are 5 zeros in this list but the list starts with 1.
Here is my code:
k = 0
for i in L1:
while i == 0:
k = k + 1
It doesn't work though. I think it is an infinite loop, but I don't know why.
Think of what will happen the first time i gets set to 0.
The while loop will start and never stop, because i is not changed within that loop.
You would be better off with something as per the following transcript, a slight modification of yours:
>>> list1 = [0,0,0,0,0,1,2]
>>> count = 0
>>> for item in list1:
... if item == 0:
... count = count + 1
... else:
... break
...
>>> print count
5
or the slightly shorter variation which breaks immediately for a non-zero value, adding one otherwise.:
>>> list1 = [0,0,0,0,0,1,2]
>>> count = 0
>>> for item in list1:
... if item != 0: break
... count = count + 1
...
>>> print count
5
As other commentators have said, the problem in your code is that you seem to misunderstand the meaning of the while keyword. That aside, for problems like these, I often prefer a more functional style:
>>> import itertools
>>> k = len(list(itertools.takewhile(lambda x: x == 0, L1)))
>>> k
5
>>> k = len(list(itertools.takewhile(lambda x: x == 0, L2)))
>>> k
0
If you are just beginning to get to know Python, playing around with what the itertools offers is well worth it.
My answer expands on paxdiablo's. Thanks to him for clarifying OP's intent with the L2 case, which I had misread.
While itertools is handy for this kind of thing, at the point you're at, I'd say mastering the basic language features is worthwhile.
In your code, you do this:
L1 = [0, 0, 0, 0, 0, 1, 2]
k = 0
for i in L1:
while i == 0:
k = k + 1
When you run that chunk of code on L1, it loops forever. Here's why:
for causes the code that's enclosed (meaning the code below that's set aside by indentation) to loop. So, your for i in L1: loop runs everything indented below it once for each thing in L1.
But, while does something similar. while tells Python to run the indented code below it over and over until the condition on the while statement is False.
So, in the case of L1, the first time through the for loop, i gets set to 0. Then, while i == 0: says to execute the code enclosed, k = k + 1, over and over again until i is no longer zero. Unfortunately, since the code in the while loop does not change the value of i, i will be zero until the end of time, so it runs forever, repeatedly adding one to k.
What you're looking for is an if statement, which will not loop. It will just run the enclosed code, or not, based on whether its test is true. So, instead of:
while i == 0:
k = k + 1
you can use
if i == 0:
k = k + 1
else:
break
Then, each time through the for loop, the code asks whether i is zero, and if so, only once, it adds one to k, then goes on to the next list element. To cover your L2 case, if you hit a number that is not zero, break exits the for loop and stops counting.
The answer presented with itertools is clever, useful, good to know, and probably what you'd want to use for very large lists, but since it appears you're just learning the language (and probably learning your first language), it's worth learning how to use for, while, and if correctly.
What you're thinking while does, is carry on as normal until the condition isn't met. What it really does, is repeat the code inside of the while as a loop until the condition isn't met.
Here's my solution, which tries to work as similarly to yours as possible, by carrying on counting until the number isn't a 0 then looking at how far it's come and breaking out of the for loop.
k = 0
for index,item in enumerate(L1):
if item != 0:
k = len(L1[:index])
break

Categories