def convert(number):
threes = '' if number % 3 else 'Pling' # Empty string if modulo == 1 (0 evaluates to False)
fives = '' if number % 5 else 'Plang'
sevens = '' if number % 7 else 'Plong'
return f'{threes}{fives}{sevens}' or str(number)
#OR#
def convert(number):
threes = 'Pling' if not number % 3 else '' # Sound if NOT modulo == 0
fives = 'Plang' if not number % 5 else ''
sevens = 'Plong' if not number % 7 else ''
return f'{threes}{fives}{sevens}' or str(number)
This is very similar to the if-statement
approach logic, but uses ternary expressions to assign either an empty string or a drop sound to a variable.
The variables are then used in an f-string
to compose the result, avoiding the use of join()
, or a loop
.
If the f-string
is empty (evaluating to False in a boolean context), a str
of the input number is returned instead.
This has O(1)
time and space complexity.
These two variations both exploit the fact that boolean True
and False
are a subtype of int
in Python.
0 evaluates to False
, and 1 to True
.
So the expression 'Pling' if not number % 3 else ''
can be read as "return 'Pling" if number % 3 not False" where False
is 0, and (not False
) is 1.
The expression '' if number % 3 else 'Pling'
is the inverse: "return '' if number % 3 is True" - where number % 3 > 0 is True
, and number % 3 == 0 is False
.
Like the if-statement
approach, these solutions are nicely readable and to-the-point, but will grow in length and get harder to read if many more factors are added or business logic changes.
The f-string
in particular could get unwieldy beyond about 5 factors.
Other solutions using data structures to hold factors and join()
to assemble strings might be a better option in 'high change' situations.