forked from PyAr/exercism
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial version taken from exercism/python
- Loading branch information
0 parents
commit 190913a
Showing
504 changed files
with
23,195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2021 Exercism | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def accumulate(collection, operation): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import unittest | ||
|
||
from accumulate import accumulate | ||
|
||
|
||
class AccumulateTest(unittest.TestCase): | ||
def test_empty_sequence(self): | ||
self.assertEqual(accumulate([], lambda x: x / 2), []) | ||
|
||
def test_pow(self): | ||
self.assertEqual( | ||
accumulate([1, 2, 3, 4, 5], lambda x: x * x), [1, 4, 9, 16, 25]) | ||
|
||
def test_divmod(self): | ||
self.assertEqual( | ||
accumulate([10, 17, 23], lambda x: divmod(x, 7)), | ||
[(1, 3), (2, 3), (3, 2)]) | ||
|
||
def test_composition(self): | ||
inp = [10, 17, 23] | ||
self.assertEqual( | ||
accumulate( | ||
accumulate(inp, lambda x: divmod(x, 7)), | ||
lambda x: 7 * x[0] + x[1]), inp) | ||
|
||
def test_capitalize(self): | ||
self.assertEqual( | ||
accumulate(['hello', 'world'], str.upper), ['HELLO', 'WORLD']) | ||
|
||
def test_recursive(self): | ||
inp = ['a', 'b', 'c'] | ||
out = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']] | ||
self.assertEqual( | ||
accumulate( | ||
inp, lambda x: accumulate(list('123'), lambda y: x + y)), out) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Instructions | ||
|
||
Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection. | ||
|
||
Given the collection of numbers: | ||
|
||
- 1, 2, 3, 4, 5 | ||
|
||
And the operation: | ||
|
||
- square a number (`x => x * x`) | ||
|
||
Your code should be able to produce the collection of squares: | ||
|
||
- 1, 4, 9, 16, 25 | ||
|
||
Check out the test suite to see the expected function signature. | ||
|
||
## Restrictions | ||
|
||
Keep your hands off that collect/map/fmap/whatchamacallit functionality provided by your standard library! | ||
Solve this one yourself using other basic tools instead. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def abbreviate(words): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# These tests are auto-generated with test data from: | ||
# https://github.com/exercism/problem-specifications/tree/main/exercises/acronym/canonical-data.json | ||
# File last updated on 2023-07-20 | ||
|
||
import unittest | ||
|
||
from acronym import ( | ||
abbreviate, | ||
) | ||
|
||
|
||
class AcronymTest(unittest.TestCase): | ||
def test_basic(self): | ||
self.assertEqual(abbreviate("Portable Network Graphics"), "PNG") | ||
|
||
def test_lowercase_words(self): | ||
self.assertEqual(abbreviate("Ruby on Rails"), "ROR") | ||
|
||
def test_punctuation(self): | ||
self.assertEqual(abbreviate("First In, First Out"), "FIFO") | ||
|
||
def test_all_caps_word(self): | ||
self.assertEqual(abbreviate("GNU Image Manipulation Program"), "GIMP") | ||
|
||
def test_punctuation_without_whitespace(self): | ||
self.assertEqual(abbreviate("Complementary metal-oxide semiconductor"), "CMOS") | ||
|
||
def test_very_long_abbreviation(self): | ||
self.assertEqual( | ||
abbreviate( | ||
"Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me" | ||
), | ||
"ROTFLSHTMDCOALM", | ||
) | ||
|
||
def test_consecutive_delimiters(self): | ||
self.assertEqual(abbreviate("Something - I made up from thin air"), "SIMUFTA") | ||
|
||
def test_apostrophes(self): | ||
self.assertEqual(abbreviate("Halley's Comet"), "HC") | ||
|
||
def test_underscore_emphasis(self): | ||
self.assertEqual(abbreviate("The Road _Not_ Taken"), "TRNT") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Instructions | ||
|
||
Convert a phrase to its acronym. | ||
|
||
Techies love their TLA (Three Letter Acronyms)! | ||
|
||
Help generate some jargon by writing a program that converts a long name like Portable Network Graphics to its acronym (PNG). | ||
|
||
Punctuation is handled as follows: hyphens are word separators (like whitespace); all other punctuation can be removed from the input. | ||
|
||
For example: | ||
|
||
| Input | Output | | ||
| ------------------------- | ------ | | ||
| As Soon As Possible | ASAP | | ||
| Liquid-crystal display | LCD | | ||
| Thank George It's Friday! | TGIF | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# Introduction | ||
|
||
There are multiple Pythonic ways to solve the Acronym exercise. | ||
Among them are: | ||
|
||
- Using `str.replace()` to scrub the input, and: | ||
- joining with a `for loop` with string concatenation via the `+` operator. | ||
- joining via `str.join()`, passing a `list-comprehension` or `generator-expression`. | ||
- joining via `str.join()`, passing `map()`. | ||
- joining via `functools.reduce()`. | ||
|
||
- Using `re.findall()`/`re.finditer()` to scrub the input, and: | ||
- joining via `str.join()`, passing a `generator-expression`. | ||
|
||
- Using `re.sub()` for both cleaning and joining (_using "only" regex for almost everything_)` | ||
|
||
|
||
## General Guidance | ||
|
||
The goal of the Acronym exercise is to collect the first letters of each word in the input phrase and return them as a single capitalized string (_the acronym_). | ||
The challenge is to efficiently identify and capitalize the first letters while removing or ignoring non-letter characters such as `'`,`-`,`_`, and white space. | ||
|
||
|
||
There are two idiomatic strategies for non-letter character removal: | ||
- Python's built-in [`str.replace()`][str-replace]. | ||
- The [`re`][re] module, (_regular expressions_). | ||
|
||
For all but the most complex scenarios, using `str.replace()` is generally more efficient than using a regular expression. | ||
|
||
|
||
Forming the final acronym is most easily done with a direct or indirect `loop`, after splitting the input into a word list via [`str.split()`][str-split]. | ||
The majority of these approaches demonstrate alternatives to the "classic" looping structure using various other iteration techniques. | ||
Some `regex` methods can avoid looping altogether, although they can become very non-performant due to excessive backtracking. | ||
|
||
Strings are _immutable_, so any method to produce an acronym will be creating and returning a new `str`. | ||
|
||
|
||
## Approach: scrub with `replace()` and join via `for` loop | ||
|
||
```python | ||
def abbreviate(to_abbreviate): | ||
phrase = to_abbreviate.replace('-', ' ').replace('_', ' ').upper().split() | ||
acronym = '' | ||
|
||
for word in phrase: | ||
acronym += word[0] | ||
|
||
return acronym | ||
``` | ||
|
||
For more information, take a look at the [loop approach][approach-loop]. | ||
|
||
|
||
## Approach: scrub with `replace()` and join via `list comprehension` or `Generator expression` | ||
|
||
|
||
```python | ||
def abbreviate(to_abbreviate): | ||
phrase = to_abbreviate.replace('-', ' ').replace('_', ' ').upper().split() | ||
|
||
return ''.join([word[0] for word in phrase]) | ||
|
||
###OR### | ||
|
||
def abbreviate(to_abbreviate): | ||
phrase = to_abbreviate.replace('-', ' ').replace('_', ' ').upper().split() | ||
|
||
# note the parenthesis instead of square brackets. | ||
return ''.join((word[0] for word in phrase)) | ||
``` | ||
|
||
For more information, check out the [list-comprehension][approach-list-comprehension] approach or the [generator-expression][approach-generator-expression] approach. | ||
|
||
|
||
## Approach: scrub with `replace()` and join via `map()` | ||
|
||
```python | ||
def abbreviate(to_abbreviate): | ||
phrase = to_abbreviate.replace("_", " ").replace("-", " ").upper().split() | ||
|
||
return ''.join(map(lambda word: word[0], phrase)) | ||
``` | ||
|
||
For more information, read the [map][approach-map-function] approach. | ||
|
||
|
||
## Approach: scrub with `replace()` and join via `functools.reduce()` | ||
|
||
```python | ||
from functools import reduce | ||
|
||
|
||
def abbreviate(to_abbreviate): | ||
phrase = to_abbreviate.replace("_", " ").replace("-", " ").upper().split() | ||
|
||
return reduce(lambda start, word: start + word[0], phrase, "") | ||
``` | ||
|
||
For more information, take a look at the [functools.reduce()][approach-functools-reduce] approach. | ||
|
||
|
||
## Approach: filter with `re.findall()` and join via `str.join()` | ||
|
||
```python | ||
import re | ||
|
||
|
||
def abbreviate(phrase): | ||
removed = re.findall(r"[a-zA-Z']+", phrase) | ||
|
||
return ''.join(word[0] for word in removed).upper() | ||
``` | ||
|
||
For more information, take a look at the [regex-join][approach-regex-join] approach. | ||
|
||
|
||
## Approach: use `re.sub()` | ||
|
||
```python | ||
import re | ||
|
||
|
||
def abbreviate_regex_sub(to_abbreviate): | ||
pattern = re.compile(r"(?<!_)\B[\w']+|[ ,\-_]") | ||
|
||
return re.sub(pattern, "", to_abbreviate.upper()) | ||
``` | ||
|
||
For more information, read the [regex-sub][approach-regex-sub] approach. | ||
|
||
|
||
## Other approaches | ||
|
||
Besides these seven idiomatic approaches, there are a multitude of possible variations using different string cleaning and joining methods. | ||
|
||
However, these listed approaches cover the majority of 'mainstream' strategies. | ||
|
||
|
||
## Which approach to use? | ||
|
||
All seven approaches are idiomatic, and show multiple paradigms and possibilities. | ||
All approaches are also `O(n)`, with `n` being the length of the input string. | ||
No matter the removal method, the entire input string must be iterated through to be cleaned and the first letters extracted. | ||
|
||
Of these strategies, the `loop` approach is the fastest, although `list-comprehension`, `map`, and `reduce` have near-identical performance for the test data. | ||
All approaches are fairly succinct and readable, although the 'classic' loop is probably the easiest understood by those coming to Python from other programming languages. | ||
|
||
|
||
The least performant for the test data was using a `generator-expression`, `re.findall` and `re.sub` (_least performant_). | ||
|
||
To compare performance of the approaches, take a look at the [Performance article][article-performance]. | ||
|
||
[approach-functools-reduce]: https://exercism.org/tracks/python/exercises/acronym/approaches/functools-reduce | ||
[approach-generator-expression]: https://exercism.org/tracks/python/exercises/acronym/approaches/generator-expression | ||
[approach-list-comprehension]: https://exercism.org/tracks/python/exercises/acronym/approaches/list-comprehension | ||
[approach-loop]: https://exercism.org/tracks/python/exercises/acronym/approaches/loop | ||
[approach-map-function]: https://exercism.org/tracks/python/exercises/acronym/approaches/map-function | ||
[approach-regex-join]: https://exercism.org/tracks/python/exercises/acronym/approaches/regex-join | ||
[approach-regex-sub]: https://exercism.org/tracks/python/exercises/acronym/approaches/regex-sub | ||
[article-performance]: https://exercism.org/tracks/python/exercises/isogram/articles/performance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
def encode(plain_text, a, b): | ||
pass | ||
|
||
|
||
def decode(ciphered_text, a, b): | ||
pass |
Oops, something went wrong.