Skip to content

Commit bf818b5

Browse files
meatball133BethanyG
authored andcommitted
start
1 parent afc8e4f commit bf818b5

File tree

6 files changed

+278
-0
lines changed

6 files changed

+278
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Ascii
2+
3+
```python
4+
def rotate(text, key)
5+
result = ""
6+
for letter in text:
7+
if letter.isalpha():
8+
if letter.isupper():
9+
result += chr((ord(letter) - 65 + key) % 26 + 65)
10+
else:
11+
result += chr((ord(letter) - 97 + key) % 26 + 97)
12+
else:
13+
result += letter
14+
return result
15+
```
16+
17+
This approach uses [ascii values][ascii], ascii stands for American Standard Code for Information Interchange.
18+
It is a character encoding standard for electronic communication.
19+
It is a 7-bit code, which means that it can represent 128 different characters.
20+
The system uses numbers to represent various characters, symbols, and other entities.
21+
22+
In ascii can you find all the downcased letter in the range between 97 and 123.
23+
While the upcased letters are in the range between 65 and 91.
24+
25+
The reason why you might not want to do this approach is that it only supports the english alphabet.
26+
27+
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`.
29+
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.
32+
33+
That is because we want to know which index in the alphabet the letter is.
34+
And if the number is over 26 we want to make sure that it is in the range of 0-26.
35+
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.
38+
After that is the new letter added to the result.
39+
40+
If the letter is a lowercased letter then is the same done but with the ascii value of 97 subtracted with the letter.
41+
42+
If the letter is not a letter then is the letter added to the result.
43+
When the loop is finished we return the result.
44+
45+
[ascii]: https://en.wikipedia.org/wiki/ASCII
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
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]:
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"introduction": {
3+
"authors": ["meatball133", "bethanyg"],
4+
"contributors": []
5+
},
6+
"approaches": [
7+
{
8+
"uuid": "ec09a4e1-6bc3-465b-a366-8ccdd2dbe093",
9+
"slug": "ascii-values",
10+
"title": "ASCII values",
11+
"blurb": "Use letters ascii value to rotate the alphabet",
12+
"authors": ["meatball133", "bethanyg"]
13+
},
14+
{
15+
"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",
19+
"authors": ["meatball133", "bethanyg"]
20+
}
21+
]
22+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Introduction
2+
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.
6+
7+
## General guidance
8+
9+
The goal of this exercise is to generate the largest and smallest palindromes from a given range of numbers.
10+
11+
## Approach: Using ascii values
12+
13+
This approach is very simple and easy to understand.
14+
it uses the ascii value of the letters to rotate them.
15+
There the numbers 65-91 in the ascii range represent downcased letters.
16+
While 97-123 represent upcased letters.
17+
18+
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.
21+
22+
```python
23+
def rotate(text, key)
24+
result = ""
25+
for letter in text:
26+
if letter.isalpha():
27+
if letter.isupper():
28+
result += chr((ord(letter) - 65 + key) % 26 + 65)
29+
else:
30+
result += chr((ord(letter) - 97 + key) % 26 + 97)
31+
else:
32+
result += letter
33+
return result
34+
```
35+
36+
## Approach: Alphabet
37+
38+
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.
39+
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.
40+
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.
44+
45+
```python
46+
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
47+
48+
def rotate(text, key):
49+
result = ""
50+
for letter in text:
51+
if letter.isalpha():
52+
if letter.isupper():
53+
result += AlPHABET[(AlPHABET.index(letter.lower()) + key) % 26].upper()
54+
else:
55+
result += AlPHABET[(AlPHABET.index(letter) + key) % 26]
56+
else:
57+
result += letter
58+
return result
59+
```
60+
61+
For more information, check the [Nested for loop approach][approach-nested-for-loop].
62+
63+
## Approach: Str translate
64+
65+
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.
68+
69+
```python
70+
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
71+
72+
def rotate(text, key):
73+
translator = AlPHABET[key:] + AlPHABET[:key]
74+
return text.translate(str.maketrans(AlPHABET + AlPHABET.upper(), translator + translator.upper()))
75+
```
76+
77+
You can read more about how to achieve this optimization in: [Nested for loop optimized][approach-nested-for-loop-optimized].
78+
79+
## Approach: Recursion
80+
81+
In this approach we use a recursive function.
82+
A recursive function is a function that calls itself.
83+
This approach can be more concise than other approaches, and may also be more readable for some audiences.
84+
85+
The reason why you might not want to use this approach is that Python has a [recursion limit][recursion-limit] with a default of 1000.
86+
87+
```python
88+
AlPHABET = "abcdefghijklmnopqrstuvwxyz"
89+
90+
def rotate(text, key):
91+
if text == "":
92+
return ""
93+
first_letter, rest = text[0], text[1:]
94+
if first_letter.isalpha():
95+
if first_letter.isupper():
96+
return AlPHABET[(AlPHABET.index(first_letter.lower()) + key) % 26].upper() + rotate(rest, key)
97+
else:
98+
return AlPHABET[(AlPHABET.index(first_letter) + key) % 26] + rotate(rest, key)
99+
else:
100+
return first_letter + rotate(rest, key)
101+
```
102+
103+
## Benchmark
104+
105+
For more information, check the [Performance article][article-performance].
106+
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
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Nested For Loop Optimized
2+
3+
This approach shows that just a few changes can improve the running time of the solution significantly.
4+
5+
```python
6+
def largest(min_factor, max_factor):
7+
if min_factor > max_factor:
8+
raise ValueError("min must be <= max")
9+
result = 0
10+
answer = []
11+
for number_a in range(max_factor, min_factor - 1,-1):
12+
was_bigger = False
13+
for number_b in range(max_factor, number_a - 1, -1):
14+
if number_a * number_b >= result:
15+
was_bigger = True
16+
test_value = str(number_a * number_b)
17+
if test_value == test_value[::-1]:
18+
if number_a * number_b > result:
19+
answer = []
20+
result = int(test_value)
21+
answer.append([number_a, number_b])
22+
if not was_bigger:
23+
break
24+
if result == 0:
25+
result = None
26+
return (result, answer)
27+
28+
29+
def smallest(min_factor, max_factor):
30+
if min_factor > max_factor:
31+
raise ValueError("min must be <= max")
32+
result = 0
33+
answer = []
34+
for number_a in range(min_factor, max_factor+1):
35+
was_smaller = False
36+
for number_b in range(min_factor, max_factor+1):
37+
if number_a * number_b <= result or result == 0:
38+
was_smaller = True
39+
test_value = str(number_a * number_b)
40+
if test_value == test_value[::-1]:
41+
if number_a * number_b < result:
42+
answer = []
43+
result = int(test_value)
44+
answer.append([number_a, number_b])
45+
if not was_smaller:
46+
break
47+
if result == 0:
48+
result = None
49+
return (result, answer)
50+
```
51+
52+
This approach is very similar to the [nested for loop approach][approach-nested-for-loop], but it has a few optimizations.
53+
To optimize the `largest` function, we have to start the inner loop from the maximum factor and proceed down to the minimum factor.
54+
This allows us to stop the inner loop earlier than before.
55+
We also set the minimum value in the _inner_ loop to the current value of the _outer_ loop.
56+
57+
Here is an example of how the algorithm works and why the loops need to be modified.
58+
Say we take maximum to be 99 and the minimum 10.
59+
In the first round:
60+
61+
```
62+
x = [99 , 98, 97 ...]
63+
y = [99]
64+
```
65+
66+
And already we have our result: `9009[91,99]`
67+
Although the loops have to continue to make us sure there are no higher values.
68+
69+
```
70+
x = [98, 97, 96 ...]
71+
y = [99, 98]
72+
...
73+
x = [90, 89, 88 ...]
74+
y = [99, 98,97,96,95,94,93,92,91,90]
75+
76+
Here we can see that the highest value for this "run" is 90 \* 99 = 8910.
77+
Meaning that running beyond this point won't give us any values higher than 9009.
78+
79+
That is why we introduce the `was_bigger` variable.
80+
With `was_bigger`, we can check if the inner loop has a bigger value than the current result.
81+
If there has not been a bigger value, we can stop the inner loop and stop the outer loop.
82+
We do that by using the [`break`][break] statement.
83+
84+
If we hadn't modified the direction of the inner loop, it would have started from the minimum factor and gone up to the maximum factor.
85+
This would mean that for every new run in the outer loop, the values would be bigger than the previous run.
86+
87+
The `smallest` function is optimized in a similar way as `largest` function compared to the original approach.
88+
The only difference is that we have to start the inner loop and outer loop from the minimum factor and go up to the maximum factor.
89+
Since what we want is the smallest value, we have to start from the smallest value and go up to the biggest value.
90+
91+
[approach-nested-for-loop]: https://exercism.org/tracks/python/exercises/palindrome-products/approaches/nested-for-loop
92+
[break]: https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
for number_a in range(max_factor, min_factor - 1,-1):
2+
was_bigger = False
3+
for number_b in range(max_factor, number_a - 1, -1):
4+
if number_a * number_b >= result:
5+
was_bigger = True

0 commit comments

Comments
 (0)