|
1 | 1 | # Introduction
|
2 | 2 |
|
3 | 3 | The objective of the Wordy exercise is to parse and evaluate small/simple mathematical word problems, returning the result as an integer.
|
4 |
| -These problems do not require complex or [PEMDAS][PEMDAS]-based evaluation and are instead processed from left-to-right _in sequence_. |
| 4 | +These questions do not require complex or [PEMDAS][PEMDAS]-based evaluation and are instead processed from left-to-right _in sequence_. |
5 | 5 | This means that for some of the test cases, the solution will not be the same as if the word problem was evaluated like a traditional math problem.
|
6 | 6 |
|
| 7 | +<br> |
| 8 | + |
7 | 9 |
|
8 | 10 | ## General Guidance
|
9 | 11 |
|
10 | 12 | The key to a Wordy solution is to remove the "question" portion of the sentence (_"What is", "?"_) and process the remaining words between numbers as [operators][mathematical operators].
|
11 |
| - |
12 |
| - |
13 | 13 | If a single number remains after removing the "question" pieces, it should be converted to an [`int`][int] and returned as the answer.
|
14 | 14 |
|
15 | 15 |
|
16 |
| -Any words or word-number combinations that do not fall into the simple mathematical evaluation pattern (_number-operator-number_) should [`raise`][raise-statement] a [`ValueError`][value-error] with a message. |
| 16 | +Any words or word-number combinations that do not fall into the simple mathematical evaluation pattern (_number-operator-number_) should [`raise`][raise-statement] a ["ValueError('syntax error")`][value-error] with a message. |
17 | 17 | This includes any "extra" spaces between numbers.
|
18 |
| - |
19 |
| - |
20 |
| -One way to reduce the number of `raise` statements/ `ValueError`s needed in the code is to determine if a problem is a "valid" question _before_ proceeding to parsing and calculation. |
21 | 18 | As shown in various approaches, there are multiple strategies for validating questions, with no one "canonical" solution.
|
22 | 19 |
|
23 | 20 |
|
24 |
| -One very effective validation approach is to check if a question starts with "What is", ends with "?", and does not include the word "cubed". |
| 21 | +A whole class of error can be eliminated up front by checking if a question starts with "What is", ends with "?", and does not include the word "cubed". |
25 | 22 | Any other question formulation becomes a `ValueError("unknown operation")`.
|
26 |
| -This very restrictive approach could lead to future maintenance issues if the definition of a question ever changes or operations are added, but for the purposes of passing the current Wordy tests, it works well. |
| 23 | +This could lead to future maintenance issues if the definition of a question ever changes or operations are added, but for the purposes of passing the current Wordy tests, it works well. |
27 | 24 |
|
28 | 25 |
|
29 |
| -Proceeding from validation, there are many Pythonic ways to go about the cleaning, parsing, and calculation steps of Wordy. |
30 |
| -However, they all follow these general steps: |
| 26 | +~~~~exercism/note |
| 27 | +There are many Pythonic ways to go about the cleaning, parsing, and calculation steps of Wordy. |
| 28 | +However, the solutions all follow these general steps: |
31 | 29 |
|
32 | 30 | 1. Remove the parts of the question string that do not apply to calculating the answer.
|
33 | 31 | 2. Iterate over the question, determining which words are numbers, and which are meant to be mathematical operations.
|
34 |
| - - _Converting the question string into a `list` of words is hugely helpful here, but not absolutely necessary._ |
35 |
| -3. **_Starting from the left_**, take the first three elements and convert number strings to `int` and operations words to +, -, *, /. |
| 32 | + -- _Converting the question string into a `list` of words is hugely helpful here._ |
| 33 | +3. **_Starting from the left_**, take the first three elements and convert number strings to `int` and operations words to the mathematical operations +, -, *, and /. |
36 | 34 | 4. Apply the operation to the numbers, which should result in a single number.
|
37 |
| - - _Employing a `try-except` block around the conversion and operator application steps can trap any errors thrown and make the code both "safer" and less complex._ |
| 35 | + -- _Employing a `try-except` block can trap any errors thrown and make the code both "safer" and less complex._ |
38 | 36 | 5. Use the calculated number from step 4 as the start for the next "trio" (_number, operation, number_) in the question. The calculated number + the remainder of the question becomes the question being worked on in the next iteration.
|
39 |
| - - _Using a `while-loop` with a test on the length of the question to do calculation is a very common strategy._ |
| 37 | + -- _Using a `while-loop` with a test on the length of the question to do calculation is a very common strategy._ |
40 | 38 | 6. Once the question is calculated down to a single number, that is the answer. Anything else that happens in the loop/iteration or within the accumulated result is a `ValueError("syntax error")`.
|
| 39 | +~~~~ |
41 | 40 |
|
42 | 41 |
|
43 |
| -For cleaning the question, [`str.removeprefix`][removeprefix] and |
| 42 | +For question cleaning, [`str.removeprefix`][removeprefix] and |
44 | 43 | [`str.removesuffix`][removesuffix] introduced in `Python 3.9` can be very useful:
|
45 | 44 |
|
46 | 45 |
|
@@ -79,20 +78,37 @@ Different combinations of [`str.find`][find], [`str.rfind`][rfind], or [`str.ind
|
79 | 78 | A [regex][regex] could be used to process the question as well, but might be considered overkill given the fixed nature of the prefix/suffix and operations.
|
80 | 79 | Finally, [`str.strip`][strip] and its variants are very useful for cleaning up any leftover leading or trailing whitespace.
|
81 | 80 |
|
82 |
| -Many solutions then use [`str.split`][split] to process the remaining "cleaned" question into a `list` for convenient looping/iteration, although other strategies can also be used. |
| 81 | +Many solutions then use [`str.split`][split] to process the remaining "cleaned" question into a `list` for convenient looping/iteration, although other strategies can also be used: |
83 | 82 |
|
84 | 83 |
|
85 |
| -For math operations, many solutions involve importing and using methods from the [operator][operator] module in combination with different looping, parsing, and substitution strategies. |
| 84 | +```python |
| 85 | +>>> sentence = "The quick brown fox jumped over the lazy dog 10 times" |
| 86 | +>>> sentence.split() |
| 87 | +['The', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'lazy', 'dog', '10', 'times'] |
| 88 | +``` |
| 89 | + |
| 90 | + |
| 91 | +For math operations, many solutions involve importing and using methods from the [operator][operator] module. |
86 | 92 | Some solutions use either [lambda][lambdas] expressions, [dunder/"special" methods][dunder-methods], or even `eval()` to replace words with arithmetic operations.
|
87 |
| -However, the exercise can be solved **without** using `operator`, `lambdas`, `dunder-methods` or `eval`. |
| 93 | + |
| 94 | + |
| 95 | +However, the exercise can be solved without using `operator`, `lambdas`, `dunder-methods` or `eval`. |
88 | 96 | It is recommended that you first start by solving it _without_ "advanced" strategies, and then refine your solution into something more compact or complex as you learn and practice.
|
89 | 97 |
|
90 | 98 |
|
91 | 99 | ~~~~exercism/caution
|
92 | 100 | Using [`eval`][eval] for the operations might seem convenient, but it is a [dangerous][eval-danger] and possibly [destructive][eval-destructive] approach.
|
93 | 101 | It is also entirely unnecessary, as the other methods described here are safer and equally performant.
|
| 102 | +
|
| 103 | +[eval-danger]: https://softwareengineering.stackexchange.com/questions/311507/why-are-eval-like-features-considered-evil-in-contrast-to-other-possibly-harmfu |
| 104 | +[eval-destructive]: https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html |
| 105 | +[eval]: https://docs.python.org/3/library/functions.html?#eval |
94 | 106 | ~~~~
|
95 | 107 |
|
| 108 | +<br> |
| 109 | + |
| 110 | +_____________ |
| 111 | + |
96 | 112 |
|
97 | 113 | ## Approach: String, List, and Dictionary Methods
|
98 | 114 |
|
|
0 commit comments