diff options
| author | Ian Goodnight <ian.goodnight@scythe.io> | 2024-06-16 14:44:45 -0400 |
|---|---|---|
| committer | Ian Goodnight <ian.goodnight@scythe.io> | 2024-06-16 14:44:45 -0400 |
| commit | d87e83206ea21bc2290ce459ffba878e94e49f95 (patch) | |
| tree | 1cdd10ba3c58cf4925668c14a886e63041aa8634 /challenge-273/iangoodnight/python | |
| parent | 194611acf9d0f7f165ac0ec595774b2c6fd5f413 (diff) | |
| download | perlweeklychallenge-club-d87e83206ea21bc2290ce459ffba878e94e49f95.tar.gz perlweeklychallenge-club-d87e83206ea21bc2290ce459ffba878e94e49f95.tar.bz2 perlweeklychallenge-club-d87e83206ea21bc2290ce459ffba878e94e49f95.zip | |
week 273
Diffstat (limited to 'challenge-273/iangoodnight/python')
| -rw-r--r-- | challenge-273/iangoodnight/python/.gitignore | 1 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/README.md | 244 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/__init__.py | 0 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/requirements.txt | 4 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/task1.py | 85 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/task2.py | 61 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/tests/__init__.py | 7 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/tests/test_task1.py | 22 | ||||
| -rw-r--r-- | challenge-273/iangoodnight/python/tests/test_task2.py | 10 |
9 files changed, 434 insertions, 0 deletions
diff --git a/challenge-273/iangoodnight/python/.gitignore b/challenge-273/iangoodnight/python/.gitignore new file mode 100644 index 0000000000..c18dd8d83c --- /dev/null +++ b/challenge-273/iangoodnight/python/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/challenge-273/iangoodnight/python/README.md b/challenge-273/iangoodnight/python/README.md new file mode 100644 index 0000000000..31ae6aed6e --- /dev/null +++ b/challenge-273/iangoodnight/python/README.md @@ -0,0 +1,244 @@ +# Perl Weekly Challenge - 273 + +Welcome to [Week #273][0] of [The Weekly Challenge][1]. + +## Task 1: Percentage of Character + +**Submitted by:** [Mohammad Sajid Anwar][2] + +You are given a string, `$str` and a character `$char`. + +Write a script to return the percentage, nearest whole, of given character in +the given string. + +**Example 1** + +``` +Input: $str = "perl", $char = "e" +Output: 25 +``` + +**Example 2** + +``` +Input: $str = "java", $char = "a" +Output: 50 +``` + +**Example 3** + +``` +Input: $str = "python", $char = "m" +Output: 0 +``` + +**Example 4** + +``` +Input: $str = "ada", $char = "a" +Output: 67 +``` + +**Example 5** + +``` +Input: $str = "ballerina", $char = "l" +Output: 22 +``` + +**Example 6** + +``` +Input: $str = "analitik", $char = "k" +Output: 13 +``` + +### Solution + +### Testing + +Our [solution][3] is intentionally designed to be simple and easy to understand. +We have defined two constants, `PERCENTAGE_FACTOR` and `ROUNDING_THRESHOLD`, to +help with the calculation of the percentage. The `percentage_of_character` +function takes two arguments, `string` and `char`, and returns the percentage of +the character in the string, rounded to the nearest whole number. Using a +declarative approach, we first calculate the length of the string and the number +of times the character appears in the string. We then calculate the percentage +of the character in the string as a decimal, convert it to a percentage, and +round it to the nearest whole number using half up rounding. It came as a +surprise to find that python implements an `even up` rounding by default, which +could lead to incorrect results. With an `even up` rounding strategy, a value of +`0.5` would be rounded down to `0`, whereas we want it to be rounded up to `1`. +The rounding method we have used is known as `half up` rounding, which rounds +`0.5` up to `1`. The function returns `0` if the string or character are empty. + +```python +PERCENTAGE_FACTOR = 100 # multiply the decimal value by 100 to get percentage +ROUNDING_THRESHOLD = 0.5 # ensure we are rounding half up, rather than even up + + +def percentage_of_character(string: str, char: str) -> int: + """Return the percentage of given character in the given string. + + Args: + string: The string to search for the character. + char: The character to search for in the string. + + Returns: + The percentage of the character in the string, rounded to the nearest + whole number. + """ + # Get the length of the string for testing and calculating the percentage + string_length = len(string) + # Return 0 if the string or character are empty + if string_length == 0 or len(char) == 0: + return 0 + # Count the number of times the character appears in the string + char_count = string.count(char) + # Calculate the percentage of the character in the string as a decimal + decimal_percentage = char_count / string_length + # Convert the decimal percentage to a percentage + percentage = decimal_percentage * PERCENTAGE_FACTOR + # Round the percentage to the nearest whole number (half up rounding) + rounded_percentage = int(percentage + ROUNDING_THRESHOLD) + + return rounded_percentage +``` + +### Testing + +We have written a comprehensive test suite to validate our solution. We have +covered both the base and extra test cases to ensure our solution works as +expected. Runnning the test suite requires the `pytest` module, which can be +installed using `pip install pytest`. + +```python +from challenge273.task1 import percentage_of_character + + +def test_examples() -> None: + """Test if function returns correct percentage of character""" + assert percentage_of_character("perl", "e") == 25 + assert percentage_of_character("java", "a") == 50 + assert percentage_of_character("python", "m") == 0 + assert percentage_of_character("ada", "a") == 67 + assert percentage_of_character("ballerina", "l") == 22 + assert percentage_of_character("analitik", "k") == 13 + + +def test_empty_string() -> None: + """Test if function returns 0 for empty string""" + assert percentage_of_character("", "a") == 0 + + +def test_empty_character() -> None: + """Test if function returns 0 for empty character""" + assert percentage_of_character("python", "") == 0 +``` + +The test suite can be run using the following command: + +```bash +$ pytest test_task1.py +``` + +## Task 2: B After A + +**Submitted by:** [Mohammad Sajid Anwar][2] + +You are given a string, `$str`. + +Write a script to return `true` if there is at least one `b`, and no `a` appears +after the first `b`. + +**Example 1** + +``` +Input: $str = "aabb" +Output: true +``` + +**Example 2** + +``` +Input: $str = "abab" +Output: false +``` + +**Example 3** + +``` +Input: $str = "aaa" +Output: false +``` + +**Example 4** + +``` +Input: $str = "bbb" +Output: true +``` + +### Solution + +Our [solution][4] is simple and easy to understand. The `b_after_a` function +takes a single argument, `string`, and returns `True` if there is at least one +`b` in the string and no `a` appears after the first `b`. We first check if +there is no `b` in the string, in which case we return `False`. We then find the +index of the first `b` in the string and slice the string after the first `b`. +Finally, we check if there is no `a` in the slice and return `True` if that is +the case; otherwise, we return `False`. + +```python +def b_after_a(string: str) -> bool: + """ + Returns `true` if there is at least one `b`, and no `a` appears after the + first `b`. + + Args: + string: The input string to check for the presence of `b` and `a`. + + Returns: + `True` if there is at least one `b`, and no `a` appears after the first + `b`; otherwise, `False`. + """ + if "b" not in string: # fails if there is no `b` in the string + return False + b_index = string.index("b") + # grab a slice of the string after the first `b` + sliced_after_b = string[b_index + 1:] + # check if there is no `a` in the slice + return "a" not in sliced_after_b +``` + +### Testing + +We have written a comprehensive test suite to validate our solution. We have +covered both the base and extra test cases to ensure our solution works as +expected. Runnning the test suite requires the `pytest` module, which can be +installed using `pip install pytest`. + +```python +from challenge273.task2 import b_after_a + + +def test_examples() -> None: + """Test if function returns correct percentage of character""" + assert b_after_a("aabb") is True + assert b_after_a("abab") is False + assert b_after_a("aaa") is False + assert b_after_a("bbb") is True +``` + +The test suite can be run using the following command: + +```bash +$ pytest test_task2.py +``` + +[0]: https://perlweeklychallenge.org/blog/perl-weekly-challenge-272/ +[1]: https://perlweeklychallenge.org +[2]: https://manwar.org/ +[3]: ./task1.py +[4]: ./task2.py + diff --git a/challenge-273/iangoodnight/python/__init__.py b/challenge-273/iangoodnight/python/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/challenge-273/iangoodnight/python/__init__.py diff --git a/challenge-273/iangoodnight/python/requirements.txt b/challenge-273/iangoodnight/python/requirements.txt new file mode 100644 index 0000000000..4631673210 --- /dev/null +++ b/challenge-273/iangoodnight/python/requirements.txt @@ -0,0 +1,4 @@ +iniconfig==2.0.0 +packaging==24.1 +pluggy==1.5.0 +pytest==8.2.2 diff --git a/challenge-273/iangoodnight/python/task1.py b/challenge-273/iangoodnight/python/task1.py new file mode 100644 index 0000000000..47f77081f6 --- /dev/null +++ b/challenge-273/iangoodnight/python/task1.py @@ -0,0 +1,85 @@ +""" +## Task 1: Percentage of Character + +**Submitted by:** [Mohammad Sajid Anwar][0] + +You are given a string, `$str` and a character `$char`. + +Write a script to return the percentage, nearest whole, of given character in +the given string. + +**Example 1** + +``` +Input: $str = "perl", $char = "e" +Output: 25 +``` + +**Example 2** + +``` +Input: $str = "java", $char = "a" +Output: 50 +``` + +**Example 3** + +``` +Input: $str = "python", $char = "m" +Output: 0 +``` + +**Example 4** + +``` +Input: $str = "ada", $char = "a" +Output: 67 +``` + +**Example 5** + +``` +Input: $str = "ballerina", $char = "l" +Output: 22 +``` + +**Example 6** + +``` +Input: $str = "analitik", $char = "k" +Output: 13 +``` + +[0]: https://manwar.org/ +""" + +PERCENTAGE_FACTOR = 100 # multiply the decimal value by 100 to get percentage +ROUNDING_THRESHOLD = 0.5 # ensure we are rounding half up, rather than even up + + +def percentage_of_character(string: str, char: str) -> int: + """Return the percentage of given character in the given string. + + Args: + string: The string to search for the character. + char: The character to search for in the string. + + Returns: + The percentage of the character in the string, rounded to the nearest + whole number. + """ + # Get the length of the string for testing and calculating the percentage + string_length = len(string) + # Return 0 if the string or character are empty + if string_length == 0 or len(char) == 0: + return 0 + # Count the number of times the character appears in the string + char_count = string.count(char) + # Calculate the percentage of the character in the string as a decimal + decimal_percentage = char_count / string_length + # Convert the decimal percentage to a percentage + percentage = decimal_percentage * PERCENTAGE_FACTOR + # Round the percentage to the nearest whole number (half up rounding) + rounded_percentage = int(percentage + ROUNDING_THRESHOLD) + + return rounded_percentage diff --git a/challenge-273/iangoodnight/python/task2.py b/challenge-273/iangoodnight/python/task2.py new file mode 100644 index 0000000000..bda082bb9e --- /dev/null +++ b/challenge-273/iangoodnight/python/task2.py @@ -0,0 +1,61 @@ +""" +## Task 2: B After A + +**Submitted by:** [Mohammad Sajid Anwar][0] + +You are given a string, `$str`. + +Write a script to return `true` if there is at least one `b`, and no `a` +appears after the first `b`. + +**Example 1** + +``` +Input: $str = "aabb" +Output: true +``` + +**Example 2** + +``` +Input: $str = "abab" +Output: false +``` + +**Example 3** + +``` +Input: $str = "aaa" +Output: false +``` + +**Example 4** + +``` +Input: $str = "bbb" +Output: true +``` + +[0]: https://manwar.org/ +""" + + +def b_after_a(string: str) -> bool: + """ + Returns `true` if there is at least one `b`, and no `a` appears after the + first `b`. + + Args: + string: The input string to check for the presence of `b` and `a`. + + Returns: + `True` if there is at least one `b`, and no `a` appears after the first + `b`; otherwise, `False`. + """ + if "b" not in string: # fails if there is no `b` in the string + return False + b_index = string.index("b") + # grab a slice of the string after the first `b` + sliced_after_b = string[b_index + 1:] + # check if there is no `a` in the slice + return "a" not in sliced_after_b diff --git a/challenge-273/iangoodnight/python/tests/__init__.py b/challenge-273/iangoodnight/python/tests/__init__.py new file mode 100644 index 0000000000..c06655e4a4 --- /dev/null +++ b/challenge-273/iangoodnight/python/tests/__init__.py @@ -0,0 +1,7 @@ +""" +Adds the parent directory to the path so that the modules can be imported from +our tests. +""" +import sys + +sys.path.append("..") diff --git a/challenge-273/iangoodnight/python/tests/test_task1.py b/challenge-273/iangoodnight/python/tests/test_task1.py new file mode 100644 index 0000000000..b27365fdac --- /dev/null +++ b/challenge-273/iangoodnight/python/tests/test_task1.py @@ -0,0 +1,22 @@ +"""Tests for task1.py""" +from python.task1 import percentage_of_character + + +def test_examples() -> None: + """Test if function returns correct percentage of character""" + assert percentage_of_character("perl", "e") == 25 + assert percentage_of_character("java", "a") == 50 + assert percentage_of_character("python", "m") == 0 + assert percentage_of_character("ada", "a") == 67 + assert percentage_of_character("ballerina", "l") == 22 + assert percentage_of_character("analitik", "k") == 13 + + +def test_empty_string() -> None: + """Test if function returns 0 for empty string""" + assert percentage_of_character("", "a") == 0 + + +def test_empty_character() -> None: + """Test if function returns 0 for empty character""" + assert percentage_of_character("python", "") == 0 diff --git a/challenge-273/iangoodnight/python/tests/test_task2.py b/challenge-273/iangoodnight/python/tests/test_task2.py new file mode 100644 index 0000000000..12dee45e22 --- /dev/null +++ b/challenge-273/iangoodnight/python/tests/test_task2.py @@ -0,0 +1,10 @@ +"""Tests for task2.py""" +from python.task2 import b_after_a + + +def test_examples() -> None: + """Test if function returns correct percentage of character""" + assert b_after_a("aabb") is True + assert b_after_a("abab") is False + assert b_after_a("aaa") is False + assert b_after_a("bbb") is True |
