Python Forum
Calculate the multiple of a number
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Calculate the multiple of a number
#1
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.
Reply
#2
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?
Reply
#3
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.
Reply
#4
(Mar-24-2020, 10:30 PM)pythonuser1 Wrote:

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
Reply
#5
(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))
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#6
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.
Reply
#7
(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
Reply
#8
Not a useful function anymore, but it could be made a generic solution for any range and any multiple.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  calculate the 10001st prime number topologh 7 6,504 Oct-05-2020, 07:41 PM
Last Post: deanhystad
  Divide a number - Multiple levels - Sum of all numbers equal to input number pythoneer 17 9,250 Apr-20-2018, 04:07 AM
Last Post: pythoneer

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020