|
1 | | -# Scrub with `replace()` and join via `functools.reduce()` |
| 1 | +# Clean with `replace()` and join via `functools.reduce()` |
2 | 2 |
|
3 | 3 |
|
4 | 4 | ```python |
5 | 5 | from functools import reduce |
6 | 6 |
|
7 | 7 |
|
8 | 8 | def abbreviate(to_abbreviate): |
9 | | - phrase = to_abbreviate.replace("_", " ").replace("-", " ").upper().split() |
| 9 | + phrase = to_abbreviate.replace("-", " ").replace("_", " ").upper().split() |
10 | 10 |
|
11 | 11 | return reduce(lambda start, word: start + word[0], phrase, "") |
12 | 12 | ``` |
13 | 13 |
|
14 | | - |
15 | | -- This approach begins by using [`str.replace()`][str-replace] to "scrub" (_remove_) non-letter characters such as `'`,`-`,`_`, and white space from `to_abbreviate`. |
16 | | -- The phrase is then upper-cased by calling [`str.upper()`][str-upper], |
| 14 | +- This approach begins by using [`str.replace()`][str-replace] on `to_abbreviate` to convert non-letter characters such as `-` and `_` into spaces. |
| 15 | +- The phrase is then upper-cased by calling [`str.upper()`][str-upper]. |
17 | 16 | - Finally, the phrase is turned into a `list` of words by calling [`str.split()`][str-split]. |
18 | 17 |
|
19 | | -The three methods above are all [chained][chaining] together, with the output of one method serving as the input to the next method in the "chain". |
20 | | -This works because both `replace()` and `upper()` return strings, and both `upper()` and `split()` take strings as arguments. |
21 | | -However, if `split()` were called first, `replace()` and `upper()` would fail, since neither method will take a `list` as input. |
| 18 | +The three methods above are all [chained][chaining] together, with each method operating on the output of the method before it in the "chain". |
| 19 | +This works because both `replace()` and `upper()` _operate on_ strings (as they are `str` methods) and _return_ strings. |
| 20 | +If `split()` was called first, `replace()` and `upper()` would fail, since they cannot operate on the `list` returned by `split()`. |
22 | 21 |
|
23 | 22 | ~~~~exercism/note |
24 | | -`re.findall()` or `re.finditer()` can also be used to "scrub" `to_abbreviate`. |
25 | | -These two methods from the `re` module will return a `list` or a lazy `iterator` of results, respectively. |
26 | | -As of this writing, both of these methods benchmark slower than using `str.replace()` for scrubbing. |
| 23 | +`re.findall()` or `re.finditer()` can also be used to clean `to_abbreviate`. |
| 24 | +These two methods from the [`re` module][re-module] will return a `list` or a lazy `iterator` of results, respectively. |
| 25 | +As of this writing, both of these methods benchmark slower than using `str.replace()` for cleaning. |
| 26 | +
|
| 27 | +[re-module]: https://docs.python.org/3/library/re.html |
27 | 28 | ~~~~ |
28 | 29 |
|
29 | 30 |
|
30 | | -Once the phrase is scrubbed and turned into a word `list`, the acronym is created via `reduce()`. |
| 31 | +Once the phrase is cleaned and turned into a word `list`, the acronym is created via `reduce()`. |
31 | 32 | `reduce()` is a method from the [`functools`][functools] module, which provides support for higher-order functions and functional programming in Python. |
32 | 33 |
|
33 | 34 |
|
34 | 35 | [`functools.reduce()`][reduce] applies an anonymous two-argument function (_the [lambda][python lambdas] in the code example_) to the items of an iterable. |
35 | | - The application of the function travels from left to right, so that the iterable becomes a single value (_it is "reduced" to a single value_). |
| 36 | +The application of the function travels from left to right, so that the iterable becomes a single value (_it is "reduced" to a single value_). |
36 | 37 |
|
37 | 38 |
|
38 | | - Using code from the example above, `reduce(lambda start, word: start + word[0], ['GNU', 'IMAGE', 'MANIPULATION', 'PROGRAM'])` would calculate `((('GNU'[0] + 'IMAGE'[0])+'MANIPULATION'[0])+'PROGRAM'[0])`, or `GIMP`. |
39 | | - The left argument, `start`, is the _accumulated value_ and the right argument, `word`, is the value from the iterable that is used to update the accumulated 'total'. |
40 | | - The optional 'initializer' value '' is used here, and is placed ahead/before the items of the iterable in the calculation, and serves as a default if the iterable that is passed is empty. |
| 39 | +Using code from the example above, `reduce(lambda start, word: start + word[0], ["GNU", "IMAGE", "MANIPULATION", "PROGRAM"])` would calculate `((("GNU"[0] + "IMAGE"[0]) + "MANIPULATION"[0]) + "PROGRAM"[0])`, or `GIMP`. |
| 40 | +The left argument, `start`, is the _accumulated value_ and the right argument, `word`, is the value from the iterable that is used to update the accumulated 'total'. |
| 41 | +The optional 'initializer' value `""` is used here, and is placed before the items of the iterable in the calculation, and serves as a default if the iterable that is passed is empty. |
41 | 42 |
|
42 | 43 |
|
43 | | -Since using `reduce()` is fairly succinct, it is put directly on the `return` line to produce the acronym rather than assigning and returning an intermediate variable. |
| 44 | +Since using `reduce()` is fairly succinct, it is put directly on the `return` line to produce the acronym, rather than assigning and returning an intermediate variable. |
44 | 45 |
|
45 | 46 |
|
46 | 47 | In benchmarks, this solution performed about as well as both the `loops` and the `list-comprehension` solutions. |
|
0 commit comments