Python: simplifying nested FOR loop? - python

I am wondering if there is a way to simplify the nested loop below. The difficulty is that the iterator for each loop depends on things from the previous loops. Here is the code:
# Find the number of combinations summing to 200 using the given list of coin
coin=[200,100,50,20,10,5,2,1]
total=[200,0,0,0,0,0,0,0]
# total[j] is the remaining sum after using the first (j-1) types of coin
# as specified by i below
count=0
# count the number of combinations
for i in range(int(total[0]/coin[0])+1):
total[1]=total[0]-i*coin[0]
for i in range(int(total[1]/coin[1])+1):
total[2]=total[1]-i*coin[1]
for i in range(int(total[2]/coin[2])+1):
total[3]=total[2]-i*coin[2]
for i in range(int(total[3]/coin[3])+1):
total[4]=total[3]-i*coin[3]
for i in range(int(total[4]/coin[4])+1):
total[5]=total[4]-i*coin[4]
for i in range(int(total[5]/coin[5])+1):
total[6]=total[5]-i*coin[5]
for i in range(int(total[6]/coin[6])+1):
total[7]=total[6]-i*coin[6]
count+=1
print count

I recommend looking at http://labix.org/python-constraint which is a Python constraint library. One of its example files is actually permutations of coinage to reach a specific amount, and it all handles it for you once you specify the rules.

You can get rid of all the int casting. An int/int is still an int in python ie integer division.
it looks like Recursion would clean this up nicly
count = 0
coin=[200,100,50,20,10,5,2,1]
total=[200,0,0,0,0,0,0,0]
def func(i):
global count,total,coin
for x in range(total[i-1]/coin[i-1]+1):
total[i]=total[i-1]-x*coin[i-1]
if (i == 7):
count += 1
else:
func(i+1)
func(1)
print count

combinations = set()
for i in range(len(coins)):
combinations = combinations | set(for x in itertools.combinations(coins, i) if sum(x) == 200)
print len(combinations)
It's a little slow, but it should work.

Related

How do i sum from one to million using min,max,and sum? (in loop)

the question: Make a list of the numbers from one to one million, and then use
min() and max() to make sure your list actually starts at one and ends at one million. Also, use
the sum() function to see how quickly Python can add a million numbers.
So here's my initial code, I do not know how to use min max or sum in this case:
one_million = []
for numbers in range(0,1000000):
counting = numbers+1
one_million.append(counting)
print(one_million)
Do it step by step.
Make a list of the numbers from one to one million
numbers = list(range(1, 1000000 + 1)) # add 1 to upper bound since range is inclusive-exclusive
and then use min() and max() to make sure your list actually starts at one and ends at one million
assert min(numbers) == 1
assert max(numbers) == 1000000
Also, use the sum() function to see how quickly python can add a million numbers
total = sum(numbers)
print(total)
range supports min, max and sum, so you don't need any loop to do this:
numbers = range(1,1000001) #Note that range gives you a number UP TO the last number
print(max(numbers))
print(min(numbers))
print(sum(numbers))
Easy
million = [n for n in range(0, 1000000 + 1)]
million_sum = sum(million)
print(million_sum)
assert min(numbers) == 1
assert max(numbers) == 1000000
I'm assuming you're doing the Python Crash Course book because this is project 4-5. I came across your post while I was looking for documentation on min and max. I thought it was great to see someone else working on the same problem so I thought I would share my code. I came up with this:
million_list = []
for num in range(1,1_000_001):
million_list.append(num)
print(min(million_list))
print(max(million_list))
print(sum(million_list))
JeffUK's answer is nice. Thanks for the info about range not requiring a for loop.
numbers = list(range(1,1000001))
print(min(numbers))
print(max(numbers))
print(sum(numbers))
#also reading the book!

Finding the product of first Million natural numbers in Python

I have just started with Python programming language. I tried to write a function which takes input either a list or multiple integers to find their product. I am trying to find the product of first million natural numbers but its displaying an MemoryError.
def product(*arg):
answer=1
if type(arg) == tuple:
arg=str(arg)
arg=arg.lstrip('[(')
arg=arg.rstrip('],)')
arg=arg.split(',')
for i in arg:
answer*=int(i)
return answer
else:
for i in arg:
answer*=int(i)
return answer
j=range(1,1000000,1)
j=list(j)
print(product(j))
Steps:
I convert the range object into list object if i am to pass a list as
argument
Now, within the function, i try to split the tuple by converting it
string.
I convert the resultant string into a list and then loop over the
elements to find the product
Q1: How to avoid the memory error as i try to find the product of first Million natural numbers?
Q2 How to improve this code?
You can use a Generator in Python.
def generate_product():
r = 1
for i in range(1,1000000):
r *= i + 1
yield r
list(generate_product())[0]
It is more memory efficient and better in terms of performance.
To calculate the product of all numbers from 1 to 1 million use a simple loop:
r = 1
for l in range(1,1000000):
r*=(i+1)
print(res)
But keep in mind that the result will be a pretty big number.
That means that your calculation might take long and the resulting number will need a lot memory.
EDIT Then i missread your question a little. This is a function that multiplies the elements in a list:
def multiply_list_elements(_list):
result = 1
for element in _list:
result*=element
return result
multiply_list_elements([1,2,3,4])
>>> 24
The memory error probably came from the huge number as #ZabirAlNazi calculated so nicely.
All of the solution is fine, but one point to make - your question is equivalent to find the factorial of 1 million.
The number of digits of n! = log10(1) + log10(2) + ... log10(n)
import math
num_dig = 1
for i in range(1,1000000):
num_dig += math.log10(i)
print(num_dig)
So, the number of digits in your answer is 5565703 (approx.).
That's only the final n, if you also want the intermediate results it will require squared memory O(m^2).
import math
ans = 1
for i in range(2,1000001):
ans *= i
print(ans)
N.B: You can approximate with logarithms and Stirling numbers with faster run-time.
A very simple solution would be:
def prod_of():
p=1
for i in range(1,1000000):
p* = i
print(p)

A function that calculates the average of a list and returns the elements that are greater than the mathematical average of the entire list

I'm trying to make a function that would calculate the average of a given list then returns all the elements within that list which are greater than the mathematical average of that list. Example:
if the given list is [1,2,3,4,5,6], the average would be 3.5. So the function should print out the numbers (4,5,6).
I've gotten as far as adding all the numbers up within the list but no matter what I do, I can't figure out how to get the average or get it to print out the numbers that are greater than the mathematical average.
This is what i have so far to add all the elements of any given list:
def accum2(seq):
total = 0
for x in seq:
total += x
return total
print (accum2([1,2,3,4,5,6]))
The expected result of print (accum2([1,2,3,4,5,6])) should be (4,5,6) but so far I just get an answer where it just adds up all the number in the given list.
Any help is greatly appreciated and thank you in advance.
The simplest way to get the average value of a list of numeric values is to use the methods:
average = sum(seq) / len(seq)
From there just use a conditional statement (you might have to sort the list first, if it is unsorted). From there you should be able to build a new list using the built in list methods.
heres some simple code which should work.
I have added comments.
originallist = [1,2,3,4,5,6] #This is your original list
outputlist = [] #This is the list which you can add correct values to
x = sum(originallist) / len(originallist) #This effectively finds you the average
for item in originallist: #Checks which items are greater than average
if item > x:
outputlist.append(item) #If greater, add to the final list
print(outputlist)
There are many correct ways to do this, one of which is shown below (Python 3).
lst = [1,2,3,4,5,6]
avg = sum(lst)/len(lst)
res = list(filter(lambda x: x > avg, lst))
print(res)
will produce
[4,5,6].
I prefer this approach because it's less verbose than loops and also can be more easily translated to a framework like Pandas or an eventual parallel implementation if such a need arises in the future (e.g., using Spark).
This is the extended version of your work:
def accum2(seq):
total = 0
for x in seq:
total += x
L=[]
for x in seq:
if x>total/len(seq):
L.append(x)
return L
print (accum2([1,2,3,4,5,6]))
But you could simply the previous one in this code:
def accum2(seq):
return [x for x in seq if x>(sum(y for y in seq)/len(seq))]
print (accum2([1,2,3,4,5,6]))

How can I Improve this Code, using While Loop?

Create a function addNumbers(x) that takes a number as an argument and adds all the integers between 1 and the number (inclusive) and returns the total number.
Examples :
addNumbers(10)
55
addNumbers(1)
1
So this is a question, I have done using while loop , and it worked fine. But I am not satisfied with my code, I also did this problem using for loop and that's okay for me, but I want to know what could be the best way to improve dis code using while loop.
def addNumbers(num):
total = 1
i = 1
while i < num:
i += 1
total += i
return total
print addNumbers(10)
And here is my for loop answer :
def addNumbers(num):
my_list = list(range(num+1) )
for i in my_list:
my_list.append(i)
return sum(my_list)
If you want an O(1) algorithm that isn't brute-force, you can use Gauss's method:
def sum_numbers(n):
return (n+1)*n//2
Usually SO isn't the place for such questions, but anyway..
You can use sum() and range(). range() will return a list of numbers from 0 to n and sum will, well, sum it.
def sumNumbers(n):
return sum(range(n+1))
EDIT: And using while loop:
def sumNumbers(n):
i = 0
sum = 0
while i <= n:
sum += i
i += 1
return sum
Make use of numpy's sum routine and a generator like so,
import numpy as np
maxNumber = 10
sumOfNumbers = np.sum([(x) for x in xrange(1, maxNumber+1)])
print sumOfNumbers
The generator gives you the list of numbers & the routine adds them for you.

Using enumerate function in while loops

I have several mathematical algorithms that use iteration to search for the right answer. Here is one example:
def Bolzano(fonction, a, b, tol=0.000001):
while abs(b - a) > tol:
m = (a + b) / 2
if sign(fonction(m)) == sign(fonction(a)):
a = m
else:
b = m
return a, b
I want to count how many times the algorithm goes through the loop to get a and b. However this is not a for function and it isn't a list, so I can't clearly indicate what objects do I want to count if I use enumerate. Is there a way to count those loops?
Note: I am not trying to change the code itself. I am really searching for a way to count iterations in a while loop, which I can then use for other cases.
The simplest answer if you need a counter outside of a for loop is to count manually using a simple variable and addition inside your while loop:
count = 0
while condition:
...
count += 1
There is an alternative case - if each step of your iteration has a meanigful value to yield, you may want your loop to be a generator, and then use for loop and enumerate(). This makes most sense where you care about which step you are on, not just the count at the end. E.g:
def produce_steps():
while condition:
...
yield step_value
for count, step_value in enumerate(produce_steps()):
...
For a counter I use count from itertools:
from itertools import count
c = count(1)
>>>next(c)
1
>>>next(c)
2
and so on...
Syntax
count(start=0, step=1)
Docs
Make an iterator that returns evenly spaced values starting with
number start.
Ref. itertools.count

Categories

Resources