Skip to content

Commit 9580dd8

Browse files
meatball133BethanyG
authored andcommitted
Added preformance article and a bunch of content to approaches
1 parent bf818b5 commit 9580dd8

File tree

16 files changed

+377
-128
lines changed

16 files changed

+377
-128
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Alphabet
2+
3+
```python
4+
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
5+
6+
def rotate(text, key):
7+
result = ""
8+
for letter in text:
9+
if letter.isalpha():
10+
if letter.isupper():
11+
result += AlPHABET[(AlPHABET.index(letter.lower()) + key) % 26].upper()
12+
else:
13+
result += AlPHABET[(AlPHABET.index(letter) + key) % 26]
14+
else:
15+
result += letter
16+
return result
17+
```
18+
19+
The approach starts with defining the a constant which holds the whole alphabets lowercase letters.
20+
After that the function `rotate` is declared, then a variable `result` is defined with the value of an empty string.
21+
22+
Then is all the letters from the text argument iterated over through a [`for loop`][for-loop].
23+
Then is checked if the letter is a letter, if it is a letter then is checked if it is a uppercased letter.
24+
25+
If it is a uppercased letter then it is converted to lowe case and finds its index in the `AlPHABET` constant.
26+
Then is the key added to the index and [modulo (`%`)][modulo] 26 is used on the result.
27+
Then is the letter at the index found in the `AlPHABET` constant and the letter is converted to upcase.
28+
29+
If the letter is a lowercased letter then it does the same process but don't convert the letter to downcase and then to uppercase.
30+
31+
If the letter is not a letter then is the letter added to the result.
32+
When the loop is finished we return the result.
33+
34+
If you only want to use english letters so could you import the alphabet instead of defining it yourself.
35+
Since in the [`string`][string] module there is a constant called [`ascii_lowercase`][ascii_lowercase] which holds the lowercased alphabet.
36+
37+
```python
38+
import string
39+
40+
AlPHABET = string.ascii_lowercase
41+
```
42+
43+
[ascii_lowercase]: https://docs.python.org/3/library/string.html#string.ascii_letters
44+
[for-loop]: https://realpython.com/python-for-loop/
45+
[modulo]: https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
46+
[string]: https://docs.python.org/3/library/string.html
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
for letter in text:
2+
if letter.isalpha():
3+
if letter.isupper():
4+
result += AlPHABET[(AlPHABET.index(letter.lower()) + key) % 26].upper()
5+
else:
6+
result += AlPHABET[(AlPHABET.index(letter) + key) % 26]
7+
else:
8+
result += letter

exercises/practice/rotational-cipher/.approaches/ascii-values/content.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Ascii
22

33
```python
4-
def rotate(text, key)
4+
def rotate(text, key):
55
result = ""
66
for letter in text:
77
if letter.isalpha():
@@ -25,16 +25,20 @@ While the upcased letters are in the range between 65 and 91.
2525
The reason why you might not want to do this approach is that it only supports the english alphabet.
2626

2727
The approach starts with defining the function `rotate`, then a variable `result` is defined with the value of an empty string.
28-
Then is all the letters from the text iterated over through a `for loop`.
28+
Then is all the letters from the text argument iterated over through a [`for loop`][for-loop].
2929
Then is checked if the letter is a letter, if it is a letter then is checked if it is a uppercased letter.
30-
If it is a uppercased letter then is `ord` used which converts a letter to an ascii and is then added with the key and the ascii value of the letter subtracted with 65.
31-
Then is the result of that modulo 26 added with 65.
30+
31+
Python has a built in function called `ord` that converts a [unicode][unicode] symbol to an integer.
32+
The unicode's first 128 characters are the same as ascii.
33+
34+
If it is a uppercased letter then is [`ord`][ord] used to convert the letters to an integer and is then added with the key and then subtracted with 65.
35+
Then is the result of that [modulo (`%`)][modulo] 26 added with 65.
3236

3337
That is because we want to know which index in the alphabet the letter is.
3438
And if the number is over 26 we want to make sure that it is in the range of 0-26.
3539
So we use modulo to make sure it is in that range.
36-
To use modulo for a range we have to make sure that it starts at zero, thereby are we subtracting the ascii value of the letter with 65.
37-
After that to get the back to a letter we add 65 and use the `chr` method which converts an ascii value to a letter.
40+
To use modulo for a range we have to make sure that it starts at zero, thereby are we subtracting the integer value of the letter with 65.
41+
After that to get the back to a letter we add 65 and use the [`chr`][chr] method which converts an an unicode value to a letter.
3842
After that is the new letter added to the result.
3943

4044
If the letter is a lowercased letter then is the same done but with the ascii value of 97 subtracted with the letter.
@@ -43,3 +47,8 @@ If the letter is not a letter then is the letter added to the result.
4347
When the loop is finished we return the result.
4448

4549
[ascii]: https://en.wikipedia.org/wiki/ASCII
50+
[chr]: https://docs.python.org/3/library/functions.html#chr
51+
[for-loop]: https://realpython.com/python-for-loop/
52+
[modulo]: https://realpython.com/python-modulo-operator/
53+
[ord]: https://docs.python.org/3/library/functions.html#ord
54+
[unicode]: https://en.wikipedia.org/wiki/Unicode
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
for number_a in range(min_factor, max_factor+1):
2-
for number_b in range(min_factor, max_factor+1):
3-
if number_a * number_b >= result:
4-
test_value = str(number_a * number_b)
5-
if test_value == test_value[::-1]:
1+
for letter in text:
2+
if letter.isalpha():
3+
if letter.isupper():
4+
result += chr((ord(letter) - 65 + key) % 26 + 65)
5+
else:
6+
result += chr((ord(letter) - 97 + key) % 26 + 97)
7+
else:
8+
result += letter

exercises/practice/rotational-cipher/.approaches/config.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,23 @@
1313
},
1414
{
1515
"uuid": "6eb99523-b12b-4e72-8ed8-3444b635b9e5",
16-
"slug": "nested-for-loop-optimized",
17-
"title": "Nested for loop optimized",
18-
"blurb": "Nested for loop optimized edition",
16+
"slug": "alphabet",
17+
"title": "Alphabet",
18+
"blurb": "Using the alphabet to rotate the alphabet",
19+
"authors": ["meatball133", "bethanyg"]
20+
},
21+
{
22+
"uuid": "e539d1a5-f497-402b-a232-7e889f4323c1",
23+
"slug": "str-translate",
24+
"title": "Str Translate",
25+
"blurb": "Using str.translate to rotate the alphabet",
26+
"authors": ["meatball133", "bethanyg"]
27+
},
28+
{
29+
"uuid": "0c74890e-d96e-47a2-a8bf-93c45dd67f94",
30+
"slug": "recursion",
31+
"title": "Recursion",
32+
"blurb": "Using Recursion to rotate the alphabet",
1933
"authors": ["meatball133", "bethanyg"]
2034
}
2135
]

exercises/practice/rotational-cipher/.approaches/introduction.md

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
# Introduction
22

3-
There are various ways to solve `palindrome-products`.
4-
This approaches document shows 2 _common_ strategies, with one being a lot more efficient than the other.
5-
That being said, neither approach here is considered canonical, and other "pythonic" approaches could be added/expanded on in the future.
3+
There are various ways to solve `rotational-cipher`.
4+
You can for example use a [ascii values][ascii], alphabet, recursion, and `str.translate`.
65

76
## General guidance
87

9-
The goal of this exercise is to generate the largest and smallest palindromes from a given range of numbers.
8+
The goal of this exercise is to rotate the letters in a string by a given key.
109

1110
## Approach: Using ascii values
1211

@@ -16,11 +15,11 @@ There the numbers 65-91 in the ascii range represent downcased letters.
1615
While 97-123 represent upcased letters.
1716

1817
The reason why you might not want to do this approach is that it only supports the english alphabet.
19-
Say we want to use the scandivanian letter: **ä**, then this approach will not work.
20-
Since **ä** has the ascii value of 132.
18+
Say we want to use the scandinavian letter: **å**, then this approach will not work.
19+
Since **å** has the ascii value of 132.
2120

2221
```python
23-
def rotate(text, key)
22+
def rotate(text, key):
2423
result = ""
2524
for letter in text:
2625
if letter.isalpha():
@@ -33,14 +32,16 @@ def rotate(text, key)
3332
return result
3433
```
3534

35+
For more information, check the [ascii values approach][approach-ascii-values].
36+
3637
## Approach: Alphabet
3738

3839
This approach is similar to the previous one, but instead of using the ascii values, it uses the index of the letter in the alphabet.
3940
It requires the storing of a string and unless you are using two strings you have to convert the letters from upper to lower case.
4041

41-
What this approach although give is the posiblity to use any alphabet.
42-
Say we want to use the scandivanian letter: **ä**, then we just add it where we want it:
43-
`abcdefghijklmnopqrstuvwxyzä` and it will rotate correctley around that.
42+
What this approach although give is the possibility to use any alphabet.
43+
Say we want to use the scandinavian letter: **å**, then we just add it where we want it:
44+
`abcdefghijklmnopqrstuvwxyzå` and it will rotate correctly around that.
4445

4546
```python
4647
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
@@ -58,13 +59,13 @@ def rotate(text, key):
5859
return result
5960
```
6061

61-
For more information, check the [Nested for loop approach][approach-nested-for-loop].
62+
For more information, check the [Alphabet approach][approach-alphabet].
6263

6364
## Approach: Str translate
6465

6566
This approach is similar to the previous one, but instead of using the index of the letter in the alphabet, it uses the `str.translate` method.
66-
The benefit of this approach is that it has no visable loop, thereby the code becomes more concise.
67-
What to note is that the `str.translate` still loops over the `string` thereby even if it is no visable loop, it doesn't mean that a method is not looping.
67+
The benefit of this approach is that it has no visible loop, thereby the code becomes more concise.
68+
What to note is that the `str.translate` still loops over the `string` thereby even if it is no visible loop, it doesn't mean that a method is not looping.
6869

6970
```python
7071
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
@@ -74,7 +75,7 @@ def rotate(text, key):
7475
return text.translate(str.maketrans(AlPHABET + AlPHABET.upper(), translator + translator.upper()))
7576
```
7677

77-
You can read more about how to achieve this optimization in: [Nested for loop optimized][approach-nested-for-loop-optimized].
78+
For more information, check the [Str translate approach][approach-str-translate].
7879

7980
## Approach: Recursion
8081

@@ -100,10 +101,16 @@ def rotate(text, key):
100101
return first_letter + rotate(rest, key)
101102
```
102103

104+
For more information, check the [Recursion approach][approach-recursion].
105+
103106
## Benchmark
104107

105108
For more information, check the [Performance article][article-performance].
106109

107-
[approach-nested-for-loop]: https://exercism.org/tracks/python/exercises/palindrome-products/approaches/nested-for-loop
108-
[approach-nested-for-loop-optimized]: https://exercism.org/tracks/python/exercises/palindrome-products/approaches/nested-for-loop-optimized
109-
[article-performance]: https://exercism.org/tracks/python/exercises/palindrome-products/articles/performance
110+
[ascii]: https://en.wikipedia.org/wiki/ASCII
111+
[approach-recursion]: https://exercism.org/tracks/python/exercises/rotational-cipher/approaches/recursion
112+
[approach-str-translate]: https://exercism.org/tracks/python/exercises/rotational-cipher/approaches/str-translate
113+
[approach-ascii-values]: https://exercism.org/tracks/python/exercises/rotational-cipher/approaches/ascii-values
114+
[approach-alphabet]: https://exercism.org/tracks/python/exercises/rotational-cipher/approaches/alphabet
115+
[article-performance]: https://exercism.org/tracks/python/exercises/rotational-cipher/articles/performance
116+
[recursion-limit]: https://docs.python.org/3/library/sys.html#sys.setrecursionlimit

exercises/practice/rotational-cipher/.approaches/nested-for-loop-optimized/content.md

Lines changed: 0 additions & 92 deletions
This file was deleted.

exercises/practice/rotational-cipher/.approaches/nested-for-loop-optimized/snippet.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Recursion
2+
3+
```python
4+
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
5+
6+
def rotate(text, key):
7+
if text == "":
8+
return ""
9+
first_letter, rest = text[0], text[1:]
10+
if first_letter.isalpha():
11+
if first_letter.isupper():
12+
return AlPHABET[(AlPHABET.index(first_letter.lower()) + key) % 26].upper() + rotate(rest, key)
13+
else:
14+
return AlPHABET[(AlPHABET.index(first_letter) + key) % 26] + rotate(rest, key)
15+
else:
16+
return first_letter + rotate(rest, key)
17+
```
18+
19+
This approach uses a very similar approach to alphabet.
20+
And uses the same logic but instead of a loop so does this approach use [concept:python/recursion]() to solve the problem.
21+
22+
Recursion is a programming technique where a function calls itself.
23+
It is a powerful technique, but can be more tricky to implement than a while loop.
24+
Recursion isn't that common in Python, it is more common in functional programming languages, like: [Elixir][elixir], [Haskell][haskell], and [Clojure][clojure].
25+
26+
Solving this exercise with recursion removes the need for a "result" variable and the instantiation of a `loop`.
27+
If the number is not equal to one, we call `<letter> + rotate(rest)`.
28+
Then the `rotate` function can execute the same code again with new values.
29+
Meaning we can get a long chain or stack of `<letter> + rotate(rest)` until the rest variable is exhausted and then the code adds `""`.
30+
That translates to something like this: `<letter> + <letter> + <letter> + <letter> + ""`.
31+
32+
In Python, we can't have a function call itself more than 1000 times by default.
33+
Code that exceeds this recursion limit will throw a [RecursionError][recursion-error].
34+
While it is possible to adjust the [recursion limit][recursion-limit], doing so risks crashing Python and may also crash your system.
35+
Casually raising the recursion limit is not recommended.
36+
37+
[clojure]: https://exercism.org/tracks/clojure
38+
[elixir]: https://exercism.org/tracks/elixir
39+
[haskell]: https://exercism.org/tracks/haskell
40+
[recursion]: https://realpython.com/python-thinking-recursively/
41+
[recursion-error]: https://docs.python.org/3/library/exceptions.html#RecursionError
42+
[recursion-limit]: https://docs.python.org/3/library/sys.html#sys.setrecursionlimit
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
first_letter, rest = text[0], text[1:]
2+
if first_letter.isalpha():
3+
if first_letter.isupper():
4+
return AlPHABET[(AlPHABET.index(first_letter.lower()) + key) % 26].upper() + rotate(rest, key)
5+
else:
6+
return AlPHABET[(AlPHABET.index(first_letter) + key) % 26] + rotate(rest, key)
7+
else:
8+
return first_letter + rotate(rest, key)

0 commit comments

Comments
 (0)