Posts: 14
Threads: 5
Joined: Mar 2020
Mar-24-2020, 10:30 PM
(This post was last modified: Mar-24-2020, 10:32 PM by pythonuser1.)
Hello,
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Les nombre multiples de n compris entre 1 et 60
def multiple(n):
for i in range(1,61):
r=i//n
if i%n==0:
print(i,r)
return(r)
print(multiple(15)) The output of the script is like this :
./multiple_nombre_v3.py
(15, 1)
(30, 2)
(45, 3)
(60, 4)
4
My script is giving the multiple of a number (here 15 for example) and the script is working.
I want to optimize it. I have these two lines print(i,r) and return(r ). Is there a way I can get rid of one of these two lines and yet have the correct output giving only the multiple of a number ? I am asking this because the return(r ) sends "4" and in the 'if condition' I did not find an another way besides "print(i,r)" to show the multiples of a number.
Posts: 6,799
Threads: 20
Joined: Feb 2020
The test for multiples is odd. Multiples of 15 will be 15, 30, 45, 60, …. There is no reason for me to test 1, 2, ...14, 15 etc. Reversing your logic to generate multiples and stop when the multiple is out of range would be a lot more efficient.
But that is not what you are asking. I'm not exactly sure what you are asking. Do you want the multiples printed out or not? Or do you want to return the multiples, say in a list, instead of printing them out? Do you want the program to return [15, 30, 45, 60] instead of 4?
Posts: 1,838
Threads: 2
Joined: Apr 2017
In general, it's better to make the function just return the values, not printing as well. Having the printing in there is extra coupling you don't need - it makes the function less reusable and harder to test.
Posts: 25
Threads: 7
Joined: Oct 2019
(Mar-24-2020, 10:30 PM)pythonuser1 Wrote: Hello,
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Les nombre multiples de n compris entre 1 et 60
def multiple(n):
for i in range(1,61):
r=i//n
if i%n==0:
print(i,r)
return(r)
print(multiple(15)) The output of the script is like this :
./multiple_nombre_v3.py
(15, 1)
(30, 2)
(45, 3)
(60, 4)
4
My script is giving the multiple of a number (here 15 for example) and the script is working.
I want to optimize it. I have these two lines print(i,r) and return(r ). Is there a way I can get rid of one of these two lines and yet have the correct output giving only the multiple of a number ? I am asking this because the return(r ) sends "4" and in the 'if condition' I did not find an another way besides "print(i,r)" to show the multiples of a number.
Just save the data in a dict, and return the dict.
( didnt change the logic how you get to the result, just added the dict )
def multiple(n):
retDict={}
for i in range(1,61):
r=i//n
if i%n==0:
retDict.update({i:r})
#print({i,r})
return(retDict)
print(multiple(50)) Output: {50: 1}
with multiple(15) you would get
Output: {15: 1, 30: 2, 45: 3, 60: 4}
You can change the output as you like. I just printed the dict
Posts: 2,125
Threads: 11
Joined: May 2017
Mar-25-2020, 10:53 AM
(This post was last modified: Mar-25-2020, 10:53 AM by DeaD_EyE.)
(Mar-24-2020, 10:30 PM)pythonuser1 Wrote: I want to optimize it. I have these two lines print(i,r) and return(r ). Is there a way I can get rid of one of these two lines and yet have the correct output giving only the multiple of a number ? I am asking this because the return(r ) sends "4" and in the 'if condition' I did not find an another way besides "print(i,r)" to show the multiples of a number. - You should use Python 3. Currently you're using Python 2.7, which is outdated since January 2020.
- Encoding comment is not needed for Python 3. All source files are encoded with utf8
- Instead of comments, you can use docstrings
- You should change the shebang to #!/usr/bin/env python3
- Your function has side effects. Side effect means, that your function modifies the environment (print to stdout) and return a value. A Pure function takes arguments, does the work and return the result. Nothing else happens beside. Easy fix: remove the print from this function
- Use better names for objects. n, i, r are bad names.
- Give the user the flexibility to call your function with different range for start and end.
- To get rid of return, you could use a generator.
#!/usr/bin/env python3
# value is a positional argument
# start and stop are keyword-only-arguments, the * does this
def multiple_of(value, *, start, stop):
"""
Les nombre multiples de value compris entre start et stop
start is inclusive
stop is inclusive
"""
for factor in range(start, stop + 1):
if factor % value == 0:
yield factor, factor // value # <- this are the values for each step
# which goes to the consumer
multi_gen = multiple_of(15, start=1, stop=60)
# multi_gen is a generator, lazy evaluation, no values yet
my_results = list(multi_gen) # list consumes the generator
print(my_results)
# a generator can be consumed only once and then it's exhausted
# if you need the elements in a different datatype as a list:
# multi_gen = multiple_of(15, start=1, stop=60)
# my_results = tuple(multi_gen)
# You can also iterate over the generator:
for result in multiple_of(15, start=1, stop=60):
print(result)
# Bonus
# You can create also a dict from the results.
# my_results_as_dict = dict(multiple_of(15, start=1, stop=60))
Posts: 6,799
Threads: 20
Joined: Feb 2020
Mar-25-2020, 07:36 PM
(This post was last modified: Mar-25-2020, 07:36 PM by deanhystad.)
A generator is the best solution as it works for any range without making huge data structures. Plus you can always use a generator to make a list. A dictionary would be silly.
The test for multiples is still goofy. The biggest optimization improvements come from algorithm. What if someone wanted multiples of a billion? The code below completes in a fraction of a second. Using the modulo test I gave up waiting after 5 minutes.
import math
def multiple_of(value, *, start=1, stop=60):
start = math.ceil(start / value) * value
while start <= stop:
yield start, start // value
start += value
multiples = [v for v, m in multiple_of(1000000000, stop=100000000000)]
print(len(multiples)) Output: 100
If all you want is the count, further optimizations are possible that eliminate looping.
Posts: 582
Threads: 1
Joined: Aug 2019
(Mar-24-2020, 10:30 PM)pythonuser1 Wrote: I want to optimize it. I have these two lines print(i,r) and return(r ). Is there a way I can get rid of one of these two lines and yet have the correct output giving only the multiple of a number ? # -*- coding: utf-8 -*-
# Les nombre multiples de n compris entre 1 et 60
def multiple(n):
return int(60/n)
print(multiple(15)) Output: 4
Posts: 6,799
Threads: 20
Joined: Feb 2020
Not a useful function anymore, but it could be made a generic solution for any range and any multiple.
|