aboutsummaryrefslogtreecommitdiff
path: root/challenge-273/iangoodnight/python
diff options
context:
space:
mode:
authorIan Goodnight <ian.goodnight@scythe.io>2024-06-16 14:44:45 -0400
committerIan Goodnight <ian.goodnight@scythe.io>2024-06-16 14:44:45 -0400
commitd87e83206ea21bc2290ce459ffba878e94e49f95 (patch)
tree1cdd10ba3c58cf4925668c14a886e63041aa8634 /challenge-273/iangoodnight/python
parent194611acf9d0f7f165ac0ec595774b2c6fd5f413 (diff)
downloadperlweeklychallenge-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/.gitignore1
-rw-r--r--challenge-273/iangoodnight/python/README.md244
-rw-r--r--challenge-273/iangoodnight/python/__init__.py0
-rw-r--r--challenge-273/iangoodnight/python/requirements.txt4
-rw-r--r--challenge-273/iangoodnight/python/task1.py85
-rw-r--r--challenge-273/iangoodnight/python/task2.py61
-rw-r--r--challenge-273/iangoodnight/python/tests/__init__.py7
-rw-r--r--challenge-273/iangoodnight/python/tests/test_task1.py22
-rw-r--r--challenge-273/iangoodnight/python/tests/test_task2.py10
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