Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions exercises/practice/raindrops/.approaches/config.json
Original file line number Diff line number Diff line change
@@ -1,56 +1,64 @@
{
"introduction": {
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
"approaches": [
{
"uuid": "afc3b20c-c84b-45b0-97e5-5c927397274c",
"slug": "if-statements",
"title": "if statements",
"blurb": "Use a series of if statements and string concatenation.",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
{
"uuid": "55b0a949-e84e-4772-8a2c-368b491d72e2",
"slug": "loop-and-fstring",
"title": "Loop and f-string",
"blurb": "Loop through a tuple and assemble output via an f-string.",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
{
"uuid": "9785ad3a-fc52-409d-bfa4-d97926a87d22",
"slug": "sequence-with-join",
"title": "Sequence(s) with str.join()",
"blurb": "Use one or more sequences and str.join() with a generator-expression.",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
{
"uuid": "b4c3608e-d4f4-4a50-8da7-66c655241950",
"slug": "truthy-and-falsey-with-fstring",
"title": "Truthy and Falsey Values with f-strings",
"blurb": "Use ternaries to build words and an f-string to assemble the result.",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
{
"uuid": "78392dda-921b-4308-bdc7-8993898987ba",
"slug": "dict-and-join",
"title": "Dict and str.join()",
"blurb": "Use a dict to hold factors:values and str.join() with a generator-expression.",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
{
"uuid": "7e485b55-6f47-4288-ac18-d9f57fbdc0c2",
"slug": "itertools-compress",
"title": "itertools.compress",
"blurb": "Use itertools.compress() with a list mask.",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
},
{
"uuid": "298fbc79-7946-4cb1-b820-e2e282b1f155",
"slug": "functools-reduce",
"title": "functools.reduce",
"blurb": "Use functools.reduce() and zip().",
"authors": ["BethanyG"]
"authors": ["BethanyG"],
"contributors": ["yrahcaz7"]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,21 @@ def convert(number):
The advantage of the generator expression is that no intermediary `list` is created in memory.
This will definitely save memory, and might also be slightly faster than a "classic" loop that appends to a `list`.


## Variation 1

Finally, this could all be done as a 'one liner'.
But this becomes both harder to read and harder to maintain:

```python
def convert(number):
return ''.join(sound for divisor, sound in
{3: 'Pling', 5: 'Plang', 7: 'Plong'}.items()
if (number % divisor == 0)) or str(number)
if number % divisor == 0) or str(number)
```

[dict-view-object]: https://docs.python.org/3/library/stdtypes.html#dictionary-view-objects
[dict.keys()]: https://docs.python.org/3/library/stdtypes.html#dict.keys
[dict-view-object]: https://docs.python.org/3/builtins/stdtypes.html#dictionary-view-objects
[dict.keys()]: https://docs.python.org/3/builtins/stdtypes.html#dict.keys
[dict]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
[generator-expressions]: https://www.pythonmorsels.com/how-write-generator-expression/
[str.join]: https://docs.python.org/3/library/stdtypes.html#str.join

[str.join]: https://docs.python.org/3/builtins/stdtypes.html#str.join
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Use functools.reduce()
# Use `functools.reduce()`


```python
from functools import reduce

def convert(number):
sounds = ('Pling','Plang','Plong')
factors = ((number % factor) == 0 for factor in (3,5,7)) #1 if no remainder, 0 if a remainder.
sounds = ('Pling', 'Plang', 'Plong')
factors = (number % factor == 0 for factor in (3, 5, 7)) # 1 if no remainder, 0 if a remainder.
result = reduce(lambda sound, item : sound + (item[0] * item[1]), zip(sounds, factors), '')

return result or str(number)
Expand All @@ -20,16 +20,16 @@ The result is then 'reduced' to a combined result string with an empty string as
If the result is empty, the number as a string is returned instead.

This is an interesting use of `functools.reduce()`, but not necessarily the most readable way to solve this exercise.
Importing `functools` adds overhead and separating the sounds from the factors risks errors as the factor list expands.
Importing `functools` adds overhead and separating the sounds from the factors risks errors if the factor list is expanded.
The syntax of `reduce()` also obfuscates string creation/concatenation.
Unless the team maintaining this code is comfortable with `functools.reduce()`, this might be better re-written using `join()`:


```python
def convert(number):
sounds = ('Pling','Plang','Plong')
factors = ((number % factor) == 0 for factor in (3,5,7))
result = ''.join((item[0] * item[1]) for item in zip(sounds, factors))
sounds = ('Pling', 'Plang', 'Plong')
factors = (number % factor == 0 for factor in (3, 5, 7))
result = ''.join(item[0] * item[1] for item in zip(sounds, factors))

return result or str(number)
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from functools import reduce

def convert(number):
sounds = ('Pling','Plang','Plong')
factors = ((number % factor) == 0 for factor in (3,5,7))
sounds = ('Pling', 'Plang', 'Plong')
factors = (number % factor == 0 for factor in (3, 5, 7))
result = reduce(lambda sound, item : sound + (item[0] * item[1]), zip(sounds, factors), '')

return result or str(number)
return result or str(number)
16 changes: 11 additions & 5 deletions exercises/practice/raindrops/.approaches/if-statements/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@ def convert(num):
```


This approach is the most straightforward or 'naive' - it replicates in code what the instructions say, using `if` statements to check the modulo for each factor.
If the number is evenly divisible by the factor (modulo == 0), the corresponding string is concatenated to _sounds_ via the `+` operator.
This approach is the most straightforward or 'naive' - it replicates in code what the instructions say, using `if` statements to check the [modulo][modulo] for each factor.
If the number is evenly divisible by the factor (`modulo == 0`), the corresponding string is concatenated to `sounds` via the `+` operator.
Sounds is returned if it is not empty (_see [Truth Value Testing][truth-value-testing] for more info_).
Otherwise, a `str` version of the input number is returned.

This, of course incurs the 'penalty' of string concatenation.
This, of course, incurs the 'penalty' of string concatenation.
But since there are only three factors to check and the strings are small, the concatenation is at a minimum.

In fact, this solution - and most others described in the approaches here - are `O(1)` time complexity.
There are a constant number of factors to iterate through, and the work that is done never increases, even as the input numbers get bigger.
This holds true for space complexity as well.


## Variation 1

The compact form for the `if` statements might be harder to read for some people.
These can be re-written to be nested, and the return can be re-written to use a ternary expression:
These can be re-written to be nested, and the return can be re-written to use a [ternary expression][conditional-expression] (also called a conditional expression):

```python
def convert(num):
Expand All @@ -41,7 +44,10 @@ def convert(num):
return sounds if sounds else str(num)
```

While this solution is nicely readable and to-the-point, it will grow in length and get harder to read if many more factors are added or business logic changes.
While this approach is nicely readable and to-the-point, it will grow in length and get harder to read if many more factors are added or business logic changes.
Other solutions using data structures to hold factors might be a better option in 'high change' situations.


[conditional-expression]: https://docs.python.org/3/reference/expressions.html#conditional-expressions
[modulo]: https://www.freecodecamp.org/news/the-python-modulo-operator-what-does-the-symbol-mean-in-python-solved/
[truth-value-testing]: https://docs.python.org/3/library/stdtypes.html#truth-value-testing
Loading
Loading