LICENSE

MIT License

Copyright Β© 2018 Oleksii Trekhleb

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.

42.7. Python programming basics#

# set up the env

import pytest
import ipytest
import unittest

ipytest.autoconfig()

42.7.1. Operators#

42.7.1.1. Implement a function to generate the Fibonacci sequence up to a specified number of terms.#

def fibonacci(n):
    """
    Generate the Fibonacci sequence up to the given number of terms.

    Args:
        n (int): The number of Fibonacci terms to generate.

    Returns:
        list: A list containing the Fibonacci sequence.

    """
    sequence = [0, 1]
    while len(sequence) < ____:
        next_num = sequence[____] + sequence[____]
        ____.append(____)
    return sequence[:n]


# Testing fibonacci function
fib_sequence = fibonacci(10)
assert fib_sequence == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34], "Fibonacci sequence test failed"
Check result by executing below... πŸ“
%%ipytest -qq

class TestFibonacci:
    def test_fibonacci_sequence(self):
        # Test case 1: Valid input
        n = 10
        expected_sequence = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

        # Act
        result = fibonacci(n)

        # Assert
        assert result == expected_sequence

    def test_fibonacci_sequence_zero_terms(self):
        # Test case 2: Zero terms
        n = 0
        expected_sequence = []

        # Act
        result = fibonacci(n)

        # Assert
        assert result == expected_sequence

    def test_fibonacci_sequence_single_term(self):
        # Test case 3: Single term
        n = 1
        expected_sequence = [0]

        # Act
        result = fibonacci(n)

        # Assert
        assert result == expected_sequence
πŸ‘©β€πŸ’» Hint

You can consider to start the Fibonacci sequence with [0, 1] and generate the next numbers using the last two elements.

42.7.1.2. Implement a function for insertion sort to sort a list in ascending order.#

def insertion_sort(arr):
    """
    Perform insertion sort on the given list.

    Args:
        arr (list): The unsorted list to be sorted in-place.

    Returns:
        None. The input list is sorted in-place.

    """
    for i in range(1, len(arr)):
        key = arr[i]
        j = ____ - ____
        while j >= 0 and arr[j] > ____:
            arr[j + 1] = arr[j]
            j -= ____
        arr[j + ____] = ____


# Testing insertion_sort function
unsorted_list = [5, 3, 8, 4, 2]
insertion_sort(unsorted_list)
assert unsorted_list == [2, 3, 4, 5, 8], "Insertion sort test failed"
Check result by executing below... πŸ“
%%ipytest -qq

class TestInsertionSort:
    def test_insertion_sort(self):
        # Test case 1: Unsorted list
        arr = [5, 3, 8, 4, 2]
        expected_sorted_list = [2, 3, 4, 5, 8]

        # Act
        insertion_sort(arr)

        # Assert
        assert arr == expected_sorted_list

    def test_insertion_sort_empty_list(self):
        # Test case 2: Empty list
        arr = []
        expected_sorted_list = []

        # Act
        insertion_sort(arr)

        # Assert
        assert arr == expected_sorted_list

    def test_insertion_sort_single_element_list(self):
        # Test case 3: Single element list
        arr = [5]
        expected_sorted_list = [5]

        # Act
        insertion_sort(arr)

        # Assert
        assert arr == expected_sorted_list

    def test_insertion_sort_sorted_list(self):
        # Test case 4: Already sorted list
        arr = [2, 3, 4, 5, 8]
        expected_sorted_list = [2, 3, 4, 5, 8]

        # Act
        insertion_sort(arr)

        # Assert
        assert arr == expected_sorted_list
πŸ‘©β€πŸ’» Hint

You can consider to iterate and compare elements, shifting them to sort the list.

42.7.1.3. Implement a function to calculate the square root of a number using the Babylonian method.#

# Inspired by SICP http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1.7
def sqrt(x):
    """
    Implement a function to calculate the square root of a given number using the Babylonian method.

    Args:
        x (float): The number for which the square root is to be calculated.

    Returns:
        float: The square root of the given number.

    """

    def average(a, b):
        return (a + b) / 2.0

    def is_good_enough(guess):
        return abs((guess * guess) - ____) < 0.001

    def improve(guess):
        return average(guess, x / guess)

    def sqrt_iter(guess):
        if is_good_enough(guess):
            return ____
        else:
            return ____(improve(____))

    return sqrt_iter(1.0)


# Testing sqrt function
assert abs(sqrt(9) - 3.0) < 0.001, "Square root test failed"
assert abs(sqrt(16) - 4.0) < 0.001, "Square root test failed"
assert abs(sqrt(25) - 5.0) < 0.001, "Square root test failed"
Check result by executing below... πŸ“
%%ipytest -qq

class TestSqrt:
    def test_sqrt(self):
        # Test case 1: Square root of 9
        x = 9
        expected_result = 3.0

        # Act
        result = sqrt(x)

        # Assert
        assert abs(result - expected_result) < 0.001

    def test_sqrt_perfect_square(self):
        # Test case 2: Square root of a perfect square (16)
        x = 16
        expected_result = 4.0

        # Act
        result = sqrt(x)

        # Assert
        assert abs(result - expected_result) < 0.001

    def test_sqrt_non_perfect_square(self):
        # Test case 3: Square root of a non-perfect square (25)
        x = 25
        expected_result = 5.0

        # Act
        result = sqrt(x)

        # Assert
        assert abs(result - expected_result) < 0.001
πŸ‘©β€πŸ’» Hint

You can consider using iterative approximation to calculate the square root.

42.7.2. String#

42.7.2.1. str.upper#

def capitalize_first_letter(string):
    """
    Capitalizes the first letter of each word in a string.

    Args:
        string (str): The input string.

    Returns:
        str: The input string with the first letter of each word capitalized.
    """
    words = string.split()
    result = []
    for ____ in words:
        capitalized_word = word[0].____() + word[1:]
        result.____(capitalized_word)
    return ' '.join(____)


sentence = "hello, world! this is a sample sentence."
assert capitalize_first_letter(sentence) == "Hello, World! This Is A Sample Sentence."
Check result by executing below... πŸ“
%%ipytest -qq

class TestCapitalizeFirstLetterper(unittest.TestCase):

    def test_string_upper_happy_case(self):
        # assign
        test_string = 'Python strings are COOL!'

        # act
        actual_result = capitalize_first_letter(test_string)

        # assert
        expected_result = 'Python Strings Are COOL!'
        self.assertEqual(actual_result, expected_result)

    def test_string_upper_none_string(self):
        # act & assert
        with self.assertRaises(Exception):
            capitalize_first_letter(None)

    def test_string_upper_empty_string(self):
        # assign
        test_string = ''

        # act
        actual_result = capitalize_first_letter(test_string)

        # assert
        expected_result = ''
        self.assertEqual(actual_result, expected_result)
πŸ‘©β€πŸ’» Hint

You can consider splitting the string into words, capitalizing the first letter of each word, and joining the words back together.

42.7.2.2. str.title#

def capitalize_words(sentence, exclude_words=None):
    """
    Capitalizes the first letter of each word in a sentence,
    excluding certain words specified in the exclude_words list.

    Args:
        sentence (str): The input sentence.
        exclude_words (list, optional): List of words to be excluded from capitalization.
            Defaults to None.

    Returns:
        str: The sentence with capitalized words.

    """
    if exclude_words is None:
        exclude_words = []

    # Split the sentence into words
    words = sentence.____

    # Capitalize the words, excluding the specified words
    capitalized_words = [word.____ if word.lower() not in exclude_words else word for word in words]

    # Join the words back into a sentence
    capitalized_sentence = ' '.____(capitalized_words)

    return capitalized_sentence


# Example and assertions
assert capitalize_words("this is a sentence") == "This Is A Sentence"
assert capitalize_words("this is a sentence", exclude_words=["is"]) == "This is A Sentence"
Check result by executing below... πŸ“
%%ipytest -qq

class TestCapitalizeWords(unittest.TestCase):

    def test_capitalize_words_default(self):
        # assign
        sentence = "this is a sentence"

        # act
        actual_result = capitalize_words(sentence)

        # assert
        expected_result = "This Is A Sentence"
        self.assertEqual(actual_result, expected_result)

    def test_capitalize_words_exclude_words(self):
        # assign
        sentence = "this is a sentence"
        exclude_words = ["is"]

        # act
        actual_result = capitalize_words(sentence, exclude_words)

        # assert
        expected_result = "This is A Sentence"
        self.assertEqual(actual_result, expected_result)
πŸ‘©β€πŸ’» Hint

Split sentence into words, capitalize each word (excluding specified words), and join them.

42.7.2.3. str.replace#

def censor_words(sentence, words):
    """
    Censors specified words in a sentence with asterisks.

    Args:
        sentence (str): The input sentence.
        words (list): The list of words to be censored.

    Returns:
        str: The sentence with censored words.
    """
    # Iterate over each word in the list of words
    for ____ in words:
        censor = '*' * len(____)  # Create a censor string of asterisks with the same length as the word
        sentence = sentence.____(____, censor)  # Replace the word with the censor string in the sentence

    return sentence


assert censor_words("Hello, World!", ["Hello", "World"]) == "*****, *****!"
assert censor_words("Python is awesome", ["Python", "awesome"]) == "****** is *******"
Check result by executing below... πŸ“
%%ipytest -qq

class TestCensorWords:
    def test_censor_words(self):
        # Test case 1: Censoring "Hello" and "World" in "Hello, World!"
        sentence = "Hello, World!"
        words = ["Hello", "World"]
        expected_result = "*****, *****!"

        # Act
        result = censor_words(sentence, words)

        # Assert
        assert result == expected_result

    def test_censor_words_partial_match(self):
        # Test case 2: Censoring "Python" and "awesome" in "Python is awesome"
        sentence = "Python is awesome"
        words = ["Python", "awesome"]
        expected_result = "****** is *******"

        # Act
        result = censor_words(sentence, words)

        # Assert
        assert result == expected_result

    def test_censor_words_no_censoring(self):
        # Test case 3: No censoring required
        sentence = "Hello, World!"
        words = ["Love", "Python"]
        expected_result = "Hello, World!"

        # Act
        result = censor_words(sentence, words)

        # Assert
        assert result == expected_result
πŸ‘©β€πŸ’» Hint

Iterate over each word in the list and replace it with a censor string of asterisks in the sentence.

42.7.2.4. str.format str.join#

def format_person_info(people_info):
    """
    Formats a list of person information into a sentence.

    Args:
        people_info (list): A list of dictionaries containing person information. Each dictionary should have 'name' and 'age' keys.

    Returns:
        str: A formatted sentence with person information.
    """
    # Format each person's information using a list comprehension
    formatted_info = ["Name: {}, Age: {}".____(person['name'], person['age']) for person in ____]

    # Join the formatted information using a comma and space
    sentence = ', '.____(formatted_info)

    return ____


people = [
    {'name': 'John Doe', 'age': 30},
    {'name': 'Jane Smith', 'age': 25},
    {'name': 'David Johnson', 'age': 35}
]
expected_output = "Name: John Doe, Age: 30, Name: Jane Smith, Age: 25, Name: David Johnson, Age: 35"
assert format_person_info(people) == expected_output
Check result by executing below... πŸ“
%%ipytest -qq

class TestFormatPersonInfo:
    def test_format_person_info(self):
        # Test case 1: Format person information
        people_info = [
            {'name': 'John Doe', 'age': 30},
            {'name': 'Jane Smith', 'age': 25},
            {'name': 'David Johnson', 'age': 35}
        ]
        expected_result = "Name: John Doe, Age: 30, Name: Jane Smith, Age: 25, Name: David Johnson, Age: 35"

        # Act
        result = format_person_info(people_info)

        # Assert
        assert result == expected_result

    def test_format_person_info_empty_list(self):
        # Test case 2: Format person information with an empty list
        people_info = []
        expected_result = ""

        # Act
        result = format_person_info(people_info)

        # Assert
        assert result == expected_result

    def test_format_person_info_single_person(self):
        # Test case 3: Format person information with a single person
        people_info = [{'name': 'John Doe', 'age': 30}]
        expected_result = "Name: John Doe, Age: 30"

        # Act
        result = format_person_info(people_info)

        # Assert
        assert result == expected_result
πŸ‘©β€πŸ’» Hint

Format each person’s information using a list comprehension, then join the formatted information using a comma and space.

42.7.2.5. str.split#

import string

def count_word_occurrences(text):
    """
    Counts the occurrences of each word in a text.

    Args:
        text (str): The input text.

    Returns:
        dict: A dictionary containing words as keys and their occurrences as values.
    """
    word_counts = {}

    # Split the text into words using split() method
    words = text.____

    # Count the occurrences of each word
    for word in ____:
        # Remove punctuation using translate() method and string.punctuation
        word = word.translate(str.maketrans('', '', string.punctuation))

        # Convert the word to lowercase
        word = word.____

        # Update the word count
        if word in word_counts:
            word_counts[word] ____ 1
        else:
            word_counts[word] ____ 1

    return word_counts


input_text = "This is a sample text. This text is just an example."
expected_output = {
    "this": 2,
    "is": 2,
    "a": 1,
    "sample": 1,
    "text": 2,
    "just": 1,
    "an": 1,
    "example": 1
}
assert count_word_occurrences(input_text) == expected_output
Check result by executing below... πŸ“
%%ipytest -qq

class TestCountWordOccurrences:
    def test_count_word_occurrences(self):
        # Test case 1: Count word occurrences in input text
        input_text = "This is a sample text. This text is just an example."
        expected_output = {
            "this": 2,
            "is": 2,
            "a": 1,
            "sample": 1,
            "text": 2,
            "just": 1,
            "an": 1,
            "example": 1
        }

        # Act
        result = count_word_occurrences(input_text)

        # Assert
        assert result == expected_output

    def test_count_word_occurrences_empty_text(self):
        # Test case 2: Count word occurrences in an empty text
        input_text = ""
        expected_output = {}

        # Act
        result = count_word_occurrences(input_text)

        # Assert
        assert result == expected_output

    def test_count_word_occurrences_same_word_repeated(self):
        # Test case 3: Count word occurrences with the same word repeated
        input_text = "word word word word"
        expected_output = {"word": 4}

        # Act
        result = count_word_occurrences(input_text)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Split the text into words using the split() method, remove punctuation using translate() method and string.punctuation, convert words to lowercase using the lower() method, and update the word count in a dictionary.

42.7.3. Numbers#

42.7.3.1. Creating formulas#

Write the following mathematical formula in Python:

\(result = 6a^3 - \frac{8b^2 }{4c} + 11\)

def calculate(a, b, c):
    """
    Calculate the value of the formula: (6 * a^3) - (8 * b^2) / (4 * c) + 11.

    Args:
        a (float or int): The value of 'a'.
        b (float or int): The value of 'b'.
        c (float or int): The value of 'c'.

    Returns:
        float: The result of the formula.

    """
    return (6 * a ____ 3) - (8 * b ____ 2) ____ (4 * c) + 11


# Testing calculate function
assert calculate(2, 3, 4) == 54.5, "calculate test failed"
assert calculate(0, 5, 2) == -14.0, "calculate test failed"
Check result by executing below... πŸ“
%%ipytest -qq

class TestCalculate(unittest.TestCase):

    def test_calculate_happy_case(self):
        # assign
        a = 2
        b = 3
        c = 4

        # act
        actual_result = calculate(a, b, c)

        # assert
        assert actual_result == 54.5, "calculate test failed"

    def test_calculate_with_str_input(self):
        # assign
        a = '2'
        b = 3
        c = 4

        # act & assert
        with pytest.raises(TypeError):
            calculate(a, b, c)

    def test_calculate_with_none_input(self):
        # assign
        a = 2
        b = None
        c = 4

        # act & assert
        with pytest.raises(TypeError):
            calculate(a, b, c)

    def test_calculate_with_invalid_c_input(self):
        # assign
        a = 2
        b = 3
        c = 0

        # act & assert
        with pytest.raises(ZeroDivisionError):
            calculate(a, b, c)

42.7.4. Lists#

42.7.4.1. list.append, list.remove, mutable#

def permutations(elements):
    """
    Generate all permutations of a list of elements.

    Args:
        elements (list): List of elements.

    Returns:
        list: List of permutations.
    """
    if len(elements) <= 1:
        return [elements]

    result = []
    for i in range(len(elements)):
        remaining = elements[____i] + elements[i+____]
        for perm in ____(remaining):
            result.____([elements[i]] + perm)

    return result


assert permutations([1, 2, 3]) == [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
assert permutations(['a', 'b', 'c']) == [['a', 'b', 'c'], ['a', 'c', 'b'], ['b', 'a', 'c'], ['b', 'c', 'a'], ['c', 'a', 'b'], ['c', 'b', 'a']]
Check result by executing below... πŸ“
%%ipytest -qq

class TestPermutations:
    def test_permutations(self):
        # Test case 1: Permutations of [1, 2, 3]
        elements = [1, 2, 3]
        expected_output = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

        # Act
        result = permutations(elements)

        # Assert
        assert result == expected_output

    def test_permutations_single_element(self):
        # Test case 2: Permutations of a single element
        elements = ['a']
        expected_output = [['a']]

        # Act
        result = permutations(elements)

        # Assert
        assert result == expected_output

    def test_permutations_empty_list(self):
        # Test case 3: Permutations of an empty list
        elements = []
        expected_output = [[]]

        # Act
        result = permutations(elements)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Generate all permutations of a list of elements by recursively swapping elements and generating permutations of the remaining list.

def remove_duplicates(lst):
    """
    Remove duplicates from a list using the `list.remove()` method.

    Args:
        lst (list): The list to remove duplicates from.

    Returns:
        list: The list with duplicates removed.
    """
    unique_list = lst[____]  # Create a copy of the original list
    for item in lst:
        while unique_list.count(item) ____ 1:
            unique_list.____(item)

    return unique_list


assert remove_duplicates([1, 2, 2, 3, 4, 4, 5]) == [1, 2, 3, 4, 5]
assert remove_duplicates(['a', 'b', 'b', 'c', 'd', 'd']) == ['a', 'b', 'c', 'd']
Check result by executing below... πŸ“
%%ipytest -qq

class TestRemoveDuplicates:
    def test_remove_duplicates(self):
        # Test case 1: Remove duplicates from [1, 2, 2, 3, 4, 4, 5]
        lst = [1, 2, 2, 3, 4, 4, 5]
        expected_output = [1, 2, 3, 4, 5]

        # Act
        result = remove_duplicates(lst)

        # Assert
        assert result == expected_output

    def test_remove_duplicates_no_duplicates(self):
        # Test case 2: Remove duplicates from a list with no duplicates
        lst = ['a', 'b', 'c', 'd']
        expected_output = ['a', 'b', 'c', 'd']

        # Act
        result = remove_duplicates(lst)

        # Assert
        assert result == expected_output

    def test_remove_duplicates_empty_list(self):
        # Test case 3: Remove duplicates from an empty list
        lst = []
        expected_output = []

        # Act
        result = remove_duplicates(lst)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Create a copy of the original list, iterate over the list items, and remove any duplicate occurrences using the list.remove() method. Return the resulting unique list.

42.7.4.2. Slice#

Create a new list without modifiying the original one.

original = ['I', 'am', 'learning', 'hacking', 'in']
# Your implementation here
modified = ____
assert original == ['I', 'am', 'learning', 'hacking', 'in']
assert modified == ['I', 'am', 'learning', 'lists', 'in', 'Python']

42.7.4.3. list.extend#

def flatten_nested_lists(nested_lists):
    """
    Flatten a list of nested lists into a single list using the `list.extend()` method.

    Args:
        nested_lists (list): The list of nested lists.

    Returns:
        list: The flattened list.
    """
    flattened_list = []
    ____ sublist in nested_lists:
        flattened_list.____(____)

    return flattened_list


assert flatten_nested_lists([[1, 2, 3], [4, 5], [6, 7, 8, 9]]) == [1, 2, 3, 4, 5, 6, 7, 8, 9]
assert flatten_nested_lists([[1], [2], [3], [4], [5]]) == [1, 2, 3, 4, 5]
Check result by executing below... πŸ“
%%ipytest -qq

class TestFlattenNestedLists:
    def test_flatten_nested_lists(self):
        # Test case 1: Flatten [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
        nested_lists = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
        expected_output = [1, 2, 3, 4, 5, 6, 7, 8, 9]

        # Act
        result = flatten_nested_lists(nested_lists)

        # Assert
        assert result == expected_output

    def test_flatten_nested_lists_empty_lists(self):
        # Test case 2: Flatten [[]]
        nested_lists = [[]]
        expected_output = []

        # Act
        result = flatten_nested_lists(nested_lists)

        # Assert
        assert result == expected_output

    def test_flatten_nested_lists_no_nested_lists(self):
        # Test case 3: Flatten [1, 2, 3, 4, 5]
        nested_lists = [1, 2, 3, 4, 5]
        expected_output = [1, 2, 3, 4, 5]

        # Act
        result = flatten_nested_lists([nested_lists])

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Initialize an empty list called flattened_list. Iterate over each sublist in the nested_lists using a loop. Extend flattened_list with each sublist using the list.extend() method. Finally, return flattened_list.

42.7.5. Dictionaries#

42.7.5.1. Populating a dictionary#

Create a dictionary by using all the given variables.

first_name = 'John'
last_name = 'Doe'
favorite_hobby = 'Python'
sports_hobby = 'gym'
age = 82
# Your implementation
my_dict = ____
assert my_dict == {
        'name': 'John Doe',
        'age': 82,
        'hobbies': ['Python', 'gym']
    }

Populating a Dictionary with Element Occurrences

def count_occurrences(lst):
    """
    Count the occurrences of elements in a list and store the counts in a dictionary.

    Args:
        lst (list): The input list.

    Returns:
        dict: A dictionary with elements as keys and their occurrences as values.
    """
    occurrences = {}
    for item in lst:
        if item in ____:
            occurrences[item] ____ 1
        else:
            occurrences[____] = 1
    return occurrences


assert count_occurrences([1, 2, 2, 3, 3, 3]) == {1: 1, 2: 2, 3: 3}
assert count_occurrences(['a', 'b', 'a', 'c', 'c']) == {'a': 2, 'b': 1, 'c': 2}
Check result by executing below... πŸ“
%%ipytest -qq

class TestCountOccurrences:
    def test_count_occurrences(self):
        # Test case 1: Count occurrences in [1, 2, 2, 3, 3, 3]
        lst = [1, 2, 2, 3, 3, 3]
        expected_output = {1: 1, 2: 2, 3: 3}

        # Act
        result = count_occurrences(lst)

        # Assert
        assert result == expected_output

    def test_count_occurrences_empty_list(self):
        # Test case 2: Count occurrences in an empty list []
        lst = []
        expected_output = {}

        # Act
        result = count_occurrences(lst)

        # Assert
        assert result == expected_output

    def test_count_occurrences_strings(self):
        # Test case 3: Count occurrences in ['a', 'b', 'a', 'c', 'c']
        lst = ['a', 'b', 'a', 'c', 'c']
        expected_output = {'a': 2, 'b': 1, 'c': 2}

        # Act
        result = count_occurrences(lst)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Iterate over the list, check if each item is already a key, and update its occurrence count.

42.7.5.2. Removing Duplicate Values from a Dictionary using β€˜del’#

def remove_duplicates(dictionary):
    """
    Remove duplicate values from a dictionary by using the `del` keyword.

    Args:
        dictionary (dict): The input dictionary.

    Returns:
        dict: The dictionary with duplicate values removed.
    """
    unique_values = set()
    duplicate_keys = []
    for key, value in dictionary.items():
        if ____ in unique_values:
            duplicate_keys.append(____)
        else:
            unique_values.add(____)
    for key in duplicate_keys:
        ____ dictionary[key]
    return dictionary


assert remove_duplicates({'a': 1, 'b': 2, 'c': 1, 'd': 3}) == {'a': 1, 'b': 2, 'd': 3}
assert remove_duplicates({'x': 'abc', 'y': 'def', 'z': 'abc'}) == {'x': 'abc', 'y': 'def'}
Check result by executing below... πŸ“
%%ipytest -qq

class TestRemoveDuplicates:
    def test_remove_duplicates(self):
        # Test case 1: Remove duplicates from {'a': 1, 'b': 2, 'c': 1, 'd': 3}
        dictionary = {'a': 1, 'b': 2, 'c': 1, 'd': 3}
        expected_output = {'a': 1, 'b': 2, 'd': 3}

        # Act
        result = remove_duplicates(dictionary)

        # Assert
        assert result == expected_output

    def test_remove_duplicates_empty_dict(self):
        # Test case 2: Remove duplicates from an empty dictionary {}
        dictionary = {}
        expected_output = {}

        # Act
        result = remove_duplicates(dictionary)

        # Assert
        assert result == expected_output

    def test_remove_duplicates_strings(self):
        # Test case 3: Remove duplicates from {'x': 'abc', 'y': 'def', 'z': 'abc'}
        dictionary = {'x': 'abc', 'y': 'def', 'z': 'abc'}
        expected_output = {'x': 'abc', 'y': 'def'}

        # Act
        result = remove_duplicates(dictionary)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Use a set to track unique values, iterate over the dictionary items, and remove duplicate keys using the del keyword.

42.7.5.3. Counting Occurrences of Elements using dict.get()#

def count_occurrences(lst):
    """
    Count the occurrences of elements in a list and store the counts in a dictionary using `dict.get()`.

    Args:
        lst (list): The input list.

    Returns:
        dict: A dictionary with elements as keys and their occurrences as values.
    """
    occurrences = {}
    for item in lst:
        occurrences[item] = occurrences.____(item, 0) ____ 1
    return occurrences


assert count_occurrences([1, 2, 2, 3, 3, 3]) == {1: 1, 2: 2, 3: 3}
assert count_occurrences(['a', 'b', 'a', 'c', 'c']) == {'a': 2, 'b': 1, 'c': 2}
Check result by executing below... πŸ“
%%ipytest -qq

class TestCountOccurrences:
    def test_count_occurrences(self):
        # Test case 1: Count occurrences in [1, 2, 2, 3, 3, 3]
        lst = [1, 2, 2, 3, 3, 3]
        expected_output = {1: 1, 2: 2, 3: 3}

        # Act
        result = count_occurrences(lst)

        # Assert
        assert result == expected_output

    def test_count_occurrences_empty_list(self):
        # Test case 2: Count occurrences in an empty list []
        lst = []
        expected_output = {}

        # Act
        result = count_occurrences(lst)

        # Assert
        assert result == expected_output

    def test_count_occurrences_strings(self):
        # Test case 3: Count occurrences in ['a', 'b', 'a', 'c', 'c']
        lst = ['a', 'b', 'a', 'c', 'c']
        expected_output = {'a': 2, 'b': 1, 'c': 2}

        # Act
        result = count_occurrences(lst)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Use the dict.get() method to retrieve the current count of an element from the dictionary and increment it by 1. Initialize the count as 0 if the element is not yet in the dictionary.

42.7.5.4. Grouping Items by Category using dict.setdefault()#

def group_by_category(items):
    """
    Group items by category using `dict.setdefault()`.

    Args:
        items (list): The input list of items.

    Returns:
        dict: A dictionary with categories as keys and lists of items as values.
    """
    categories = {}
    for item in items:
        category = ____.get('category')
        categories.____(category, []).____(item)
    return categories


items = [
    {'name': 'Item 1', 'category': 'Category A'},
    {'name': 'Item 2', 'category': 'Category B'},
    {'name': 'Item 3', 'category': 'Category A'},
    {'name': 'Item 4', 'category': 'Category B'},
    {'name': 'Item 5', 'category': 'Category A'},
]

result = group_by_category(items)
expected_result = {
    'Category A': [
        {'name': 'Item 1', 'category': 'Category A'},
        {'name': 'Item 3', 'category': 'Category A'},
        {'name': 'Item 5', 'category': 'Category A'}
    ],
    'Category B': [
        {'name': 'Item 2', 'category': 'Category B'},
        {'name': 'Item 4', 'category': 'Category B'}
    ]
}

assert result == expected_result
Check result by executing below... πŸ“
%%ipytest -qq

class TestGroupByCategory:
    def test_group_by_category(self):
        # Test case 1: Group items by category
        items = [
            {'name': 'Item 1', 'category': 'Category A'},
            {'name': 'Item 2', 'category': 'Category B'},
            {'name': 'Item 3', 'category': 'Category A'},
            {'name': 'Item 4', 'category': 'Category B'},
            {'name': 'Item 5', 'category': 'Category A'},
        ]
        expected_output = {
            'Category A': [
                {'name': 'Item 1', 'category': 'Category A'},
                {'name': 'Item 3', 'category': 'Category A'},
                {'name': 'Item 5', 'category': 'Category A'}
            ],
            'Category B': [
                {'name': 'Item 2', 'category': 'Category B'},
                {'name': 'Item 4', 'category': 'Category B'}
            ]
        }

        # Act
        result = group_by_category(items)

        # Assert
        assert result == expected_output

    def test_group_by_category_empty_input(self):
        # Test case 2: Empty input list
        items = []
        expected_output = {}

        # Act
        result = group_by_category(items)

        # Assert
        assert result == expected_output

    def test_group_by_category_single_category(self):
        # Test case 3: Only one category present
        items = [
            {'name': 'Item 1', 'category': 'Category A'},
            {'name': 'Item 2', 'category': 'Category A'},
            {'name': 'Item 3', 'category': 'Category A'}
        ]
        expected_output = {
            'Category A': [
                {'name': 'Item 1', 'category': 'Category A'},
                {'name': 'Item 2', 'category': 'Category A'},
                {'name': 'Item 3', 'category': 'Category A'}
            ]
        }

        # Act
        result = group_by_category(items)

        # Assert
        assert result == expected_output

    def test_group_by_category_no_category(self):
        # Test case 4: No category present in items
        items = [
            {'name': 'Item 1'},
            {'name': 'Item 2'},
            {'name': 'Item 3'}
        ]
        expected_output = {
            None: [
                {'name': 'Item 1'},
                {'name': 'Item 2'},
                {'name': 'Item 3'}
            ]
        }

        # Act
        result = group_by_category(items)

        # Assert
        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Use the dict.setdefault() method to retrieve the list of items for a category. If the category doesn’t exist in the dictionary, it will be added with an empty list as the default value. Append the current item to the list of items for the corresponding category.

42.7.5.5. Accessing and Merging Dictionaries into a Single Dictionary#

def merge_dicts(*dicts):
    """
    Merge multiple dictionaries into a single dictionary.

    Args:
        *dicts: Multiple dictionaries to merge.

    Returns:
        dict: The merged dictionary.
    """
    merged_dict = {}
    for dictionary in dicts:
        for key, value in dictionary.items():
            if ____ in ____:
                if isinstance(value, dict) and isinstance(merged_dict[____], dict):
                    merged_dict[____] = merge_dicts(merged_dict[____], value)
                elif isinstance(value, list) and isinstance(merged_dict[____], list):
                    merged_dict[____].____(value)
                else:
                    merged_dict[key] = ____
            else:
                merged_dict[key] = ____
    return merged_dict


dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 5, 'd': 6}

result = merge_dicts(dict1, dict2, dict3)
expected_result = {'a': 1, 'b': 3, 'c': 5, 'd': 6}

assert result == expected_result
Check result by executing below... πŸ“
%%ipytest -qq

class TestMergeDicts:

    def test_merge_two_dicts(self):
        # Test case 1: Merge two dictionaries
        dict1 = {'a': 1, 'b': 2}
        dict2 = {'b': 3, 'c': 4}
        expected_output = {'a': 1, 'b': 3, 'c': 4}

        result = merge_dicts(dict1, dict2)

        assert result == expected_output

    def test_merge_three_dicts(self):
        # Test case 2: Merge three dictionaries
        dict1 = {'a': 1, 'b': 2}
        dict2 = {'b': 3, 'c': 4}
        dict3 = {'c': 5, 'd': 6}
        expected_output = {'a': 1, 'b': 3, 'c': 5, 'd': 6}

        result = merge_dicts(dict1, dict2, dict3)

        assert result == expected_output

    def test_merge_nested_dicts(self):
        # Test case 3: Merge dictionaries with nested dictionaries
        dict1 = {'a': 1, 'b': 2}
        dict2 = {'b': 3, 'c': 4}
        dict4 = {'e': {'f': 7}}
        dict5 = {'e': {'g': 8}}
        expected_output = {'a': 1, 'b': 3, 'c': 4, 'e': {'f': 7, 'g': 8}}

        result = merge_dicts(dict1, dict2, dict4, dict5)

        assert result == expected_output

    def test_merge_dicts_with_lists(self):
        # Test case 4: Merge dictionaries with lists
        dict1 = {'a': 1, 'b': 2}
        dict2 = {'b': 3, 'c': 4}
        dict6 = {'h': [9, 10]}
        dict7 = {'h': [11, 12]}
        expected_output = {'a': 1, 'b': 3, 'c': 4, 'h': [9, 10, 11, 12]}

        result = merge_dicts(dict1, dict2, dict6, dict7)

        assert result == expected_output
πŸ‘©β€πŸ’» Hint

Use nested loops to iterate over the dictionaries and their key-value pairs. Check if the key already exists in the merged dictionary using the in operator. Handle the conflict based on the types of values using isinstance().

42.7.6. Acknowledgments#

Thanks to below awesome open source projects for Python learning, which inspire this chapter.