The most common and widely accepted structure found in Python scripts from a high-level point of view looks something like:
# functions and classes, aka "library code"
if __name__ == "__main__":
# part that is supposed to be run as script
Your code on the other hand does not follow this structure since there is some script code at the top (
start = time.time()), then come your functions, followed by another block of script code. I highly recommend to follow that structure.
Further reading: Explanation of
if __name__ == "__main__": from the official Python documentation.
The code itself
The most striking aspect of
bouncy from a stylistic point is the capital
N as parameter name that goes against the official Style Guide for Python Code (often just called PEP8). Usually parameter and variable names are written in
snake_case, e.g. small letters, possibly separated by underscores.
With that said, let's look at the actual algorithm:
number = list(str(N))
n1 = list(str(N))
n2 = list(str(N))
Lots of repeated code here. An easy way out would be to do the conversion once, and copy the results afterwards. This can be done using slicing like
n1 = number[:], the
n1 = list(number) or the
copy module. Also,
sorted would create a copy indirectly, so no need to do this manually (see the next point).
The next thing you do in your code is sorting those lists. Once ascending, then descending. Since the second one should by definition be the mirror of the previous one, you can use slicing again to avoid that second sort.
sorted_number = sorted(number) # <- also does a copy
Oh, and did you know that
sorted does work on strings as well and simply returns a new list? (
sorted_number = sorted(N))
You could also use the result of the condition directly as return value of your function.
With some other minor changes you might end up with something like
'''Function determines whether arbitrary number N is a bouncy number.'''
digits = list(str(number))
sorted_digits = sorted(digits)
return digits != sorted_digits and digits != sorted_digits[::-1]
find is almost as straightforward as it gets. I would advise to change the variable name
n_bouncy now that the checking function is called
current would also likely be a better name for
find_bouncy_boundary, maybe even with an optional "expected bounciness percentage" might be worth a thought.
From an optimization point of view, you could also start from 1000 if you're only looking for that 99%, since the task description tells you that there are exactly 525 bouncy numbers below 1000 ;-) But there is likely not much to gain from that.
Now all there is left to do is to take the spread out script code, wrap it up in
if __name__ == "__main__":, and collect it at the bottom of the script:
if __name__ == "__main__":
start = time.time()
print(time.time() - start)
If the script part becomes more complex, this part is often put into a separate