You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: exercises/practice/wordy/.approaches/introduction.md
+53-36Lines changed: 53 additions & 36 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,17 +8,39 @@ This means that for some of the test cases, the solution will not be the same as
8
8
## General Guidance
9
9
10
10
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
-
If a single number remains after removing the "question", it should be converted to an [`int`][int] and returned as the answer.
11
+
12
+
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
+
15
+
12
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.
13
17
This includes any "extra" spaces between numbers.
14
18
19
+
15
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.
16
21
As shown in various approaches, there are multiple strategies for validating questions, with no one "canonical" solution.
17
-
One very effective approach is to check if a question starts with "What is", ends with "?", and includes only valid operations.
18
-
That 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.
19
22
20
-
There are various Pythonic ways to go about the cleaning, parsing, and calculation steps of Wordy.
21
-
For cleaning the "question" portion of the problem, [`str.removeprefix`][removeprefix] and
23
+
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".
25
+
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.
27
+
28
+
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:
31
+
32
+
1. Remove the parts of the question string that do not apply to calculating the answer.
33
+
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 +, -, *, /.
36
+
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._
38
+
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._
40
+
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")`.
41
+
42
+
43
+
For cleaning the question, [`str.removeprefix`][removeprefix] and
22
44
[`str.removesuffix`][removesuffix] introduced in `Python 3.9` can be very useful:
23
45
24
46
@@ -53,73 +75,70 @@ You can also use [`str.startswith`][startswith] and [`str.endswith`][endswith] i
53
75
```
54
76
55
77
56
-
Different combinations of [`str.find`][find], [`str.rfind`][rfind], or [`str.index`][index] with string slicing could be used to clean up the initial word problem.
57
-
A [regex][regex] could also be used to process the question, but might be considered overkill given the fixed nature of the prefix/suffix and operations.
78
+
Different combinations of [`str.find`][find], [`str.rfind`][rfind], or [`str.index`][index] with string slicing could also be used to clean up the initial question.
79
+
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.
58
80
Finally, [`str.strip`][strip] and its variants are very useful for cleaning up any leftover leading or trailing whitespace.
59
81
60
-
Many solutions then use [`str.split`][split] to process the remaining "cleaned" question into a `list` for convenient iteration, although other strategies are also used.
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.
83
+
61
84
62
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.
63
-
Some solutions use either [lambda][lambdas] expressions or [dunder/"special" methods][dunder-methods] to replace words with arithmetic operations.
64
-
However, the exercise can be solved without using `operator`, `lambdas`, or `dunder-methods`.
86
+
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`.
88
+
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
+
65
90
91
+
~~~~exercism/caution
66
92
Using [`eval`][eval] for the operations might seem convenient, but it is a [dangerous][eval-danger] and possibly [destructive][eval-destructive] approach.
67
93
It is also entirely unnecessary, as the other methods described here are safer and equally performant.
This approach uses only data structures and methods (_[dict][dict], [dict.get()][dict-get] and [list()][list]_) from core Python, and does not import any extra modules.
137
+
This approach uses only data structures and methods (_[str methods][str-methods], [list()][list], loops, etc._) from core Python, and does not import any extra modules.
120
138
It may have more lines of code than average, but it is clear to follow and fairly straightforward to reason about.
121
139
It does use a [try-except][handling-exceptions] block for handling unknown operators.
122
-
As an alternative to the `formula` loop-append, a [list-comprehension][list-comprehension] can be used to create the initial parsed formula.
140
+
141
+
Alternatives could use a [dictionary][dict] to store word --> operator mappings that could be looked up in the `while-loop` using [`<dict>.get()`][dict-get], among other strategies.
123
142
124
143
For more details and variations, read the [String, List and Dictionary Methods][approach-string-list-and-dict-methods] approach.
125
144
@@ -350,7 +369,7 @@ def answer(question):
350
369
```
351
370
352
371
353
-
This approach replaces the `while-loop` used in many solutions (_or the `recursion` strategy outlined in the approach above_) with a call to [`functools.reduce`][functools-reduce].
372
+
This approach replaces the `while-loop` used in many solutions (_or the `recursion` strategy outlined in the approach above_) with a call to [`functools.reduce`][functools-reduce].
354
373
It also employs a lookup dictionary for methods imported from the `operator` module, as well as a `list-comprehension`, the built-in [`filter`][filter] function, and multiple string [slices][sequence-operations].
355
374
If desired, the `operator` imports can be replaced with a dictionary of `lambda` expressions or `dunder-methods`.
356
375
@@ -418,9 +437,6 @@ For more detail on this solution, take a look at the [dunder method with `__geta
0 commit comments