From 3b124383cd78c48b6f94c995c4cc8f61e01c4d2f Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Sun, 16 Aug 2020 00:48:27 +0500 Subject: [PATCH 01/55] added type hints for backtracking/minimax.py --- backtracking/minimax.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 4cec0e403ddf..4019dd15aef0 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,5 @@ import math +from typing import List """ Minimax helps to achieve maximum score in a game by checking all possible moves depth is current depth in game tree. @@ -9,24 +10,24 @@ """ -def minimax(Depth, nodeIndex, isMax, scores, height): +def minimax(depth: int, node_index: int, is_max: bool, + scores: List[int], height: float) -> int: + if depth == height: + return scores[node_index] - if Depth == height: - return scores[nodeIndex] - - if isMax: + if is_max: return max( - minimax(Depth + 1, nodeIndex * 2, False, scores, height), - minimax(Depth + 1, nodeIndex * 2 + 1, False, scores, height), + minimax(depth + 1, node_index * 2, False, scores, height), + minimax(depth + 1, node_index * 2 + 1, False, scores, height), ) + return min( - minimax(Depth + 1, nodeIndex * 2, True, scores, height), - minimax(Depth + 1, nodeIndex * 2 + 1, True, scores, height), + minimax(depth + 1, node_index * 2, True, scores, height), + minimax(depth + 1, node_index * 2 + 1, True, scores, height), ) if __name__ == "__main__": - scores = [90, 23, 6, 33, 21, 65, 123, 34423] height = math.log(len(scores), 2) From 92821068e49403b68a2440dfc801a04c2674aea7 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 26 Aug 2020 23:03:25 +0500 Subject: [PATCH 02/55] added some simple test cases --- backtracking/minimax.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 4019dd15aef0..f9611541e426 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -12,6 +12,35 @@ def minimax(depth: int, node_index: int, is_max: bool, scores: List[int], height: float) -> int: + """ + >>> scores = [90, 23, 6, 33, 21, 65, 123, 34423] + >>> height = math.log(len(scores), 2) + >>> minimax(0, 0, True, scores, height) + 65 + >>> minimax(-1, 0, True, scores, height) + Traceback (most recent call last): + ... + ValueError: Depth cannot be less than 0 + >>> minimax(0, 0, True, [], 2) + Traceback (most recent call last): + ... + ValueError: Scores cannot be empty + >>> scores = [3, 5, 2, 9, 12, 5, 23, 23] + >>> height = math.log(len(scores), 2) + >>> minimax(0, 0, True, scores, height) + 12 + >>> minimax('1', 2, True, [], 2 ) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + """ + + if depth < 0: + raise ValueError("Depth cannot be less than 0") + + if len(scores) == 0: + raise ValueError("Scores cannot be empty") + if depth == height: return scores[node_index] @@ -28,8 +57,6 @@ def minimax(depth: int, node_index: int, is_max: bool, if __name__ == "__main__": - scores = [90, 23, 6, 33, 21, 65, 123, 34423] - height = math.log(len(scores), 2) + import doctest - print("Optimal value : ", end="") - print(minimax(0, 0, True, scores, height)) + doctest.testmod() From 36168219c6fe7759527b0afa34c365b8d67d35a4 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 26 Aug 2020 23:10:41 +0500 Subject: [PATCH 03/55] flake fix --- backtracking/minimax.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index f9611541e426..64c05ebf1d6c 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,3 @@ -import math from typing import List """ Minimax helps to achieve maximum score in a game by checking all possible moves From 862545f9ecf956a382bf2ac3bef13f55186fabf8 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 26 Aug 2020 23:23:31 +0500 Subject: [PATCH 04/55] fixes doctests --- backtracking/minimax.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 64c05ebf1d6c..fd7abad12b61 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -12,6 +12,7 @@ def minimax(depth: int, node_index: int, is_max: bool, scores: List[int], height: float) -> int: """ + >>> import math >>> scores = [90, 23, 6, 33, 21, 65, 123, 34423] >>> height = math.log(len(scores), 2) >>> minimax(0, 0, True, scores, height) From 80daa5750a8e5ee6ffcbcad72b2b52540d0b502d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E4=B9=88=E5=B0=8F=E5=84=BF=E9=83=8EEL?= Date: Tue, 1 Sep 2020 00:55:56 +0800 Subject: [PATCH 05/55] Fix bugs and add related tests (#2375) --- sorts/radix_sort.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sorts/radix_sort.py b/sorts/radix_sort.py index c379c679787f..0ddf996cf1ee 100644 --- a/sorts/radix_sort.py +++ b/sorts/radix_sort.py @@ -7,11 +7,13 @@ def radix_sort(list_of_ints: List[int]) -> List[int]: True radix_sort(reversed(range(15))) == sorted(range(15)) True + radix_sort([1,100,10,1000]) == sorted([1,100,10,1000]) + True """ RADIX = 10 placement = 1 max_digit = max(list_of_ints) - while placement < max_digit: + while placement <= max_digit: # declare and initialize empty buckets buckets = [list() for _ in range(RADIX)] # split list_of_ints between the buckets From e92e433dbefacc61510466d6feccf27a5506e11a Mon Sep 17 00:00:00 2001 From: Muskan Kumar <31043527+muskanvk@users.noreply.github.com> Date: Tue, 1 Sep 2020 01:04:44 +0530 Subject: [PATCH 06/55] Update CONTRIBUTING.md (#2378) * Update CONTRIBUTING.md fixed dead link to the license * Update README.md Added License * Update README.md * Update README.md * Update README.md * Update CONTRIBUTING.md Co-authored-by: Christian Clauss --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63f60c51f8e6..f8469d97ddb4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ We are very happy that you consider implementing algorithms and data structure f - You did your work - no plagiarism allowed - Any plagiarized work will not be merged. -- Your work will be distributed under [MIT License](License) once your pull request is merged +- Your work will be distributed under [MIT License](LICENSE.md) once your pull request is merged - You submitted work fulfils or mostly fulfils our styles and standards **New implementation** is welcome! For example, new solutions for a problem, different representations for a graph data structure or algorithm designs with different complexity. From a1d1a44f515b5769136c90342bc1955e3bc8a26e Mon Sep 17 00:00:00 2001 From: Shubham Shaswat Date: Wed, 2 Sep 2020 23:03:12 +0530 Subject: [PATCH 07/55] added idf-smooth (#2174) * added idf-smooth * added idf-smooth * added idf-smooth --- machine_learning/word_frequency_functions.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/machine_learning/word_frequency_functions.py b/machine_learning/word_frequency_functions.py index e9e9e644b7d8..9cf7b694c6be 100644 --- a/machine_learning/word_frequency_functions.py +++ b/machine_learning/word_frequency_functions.py @@ -83,16 +83,17 @@ def document_frequency(term: str, corpus: str) -> int: return (len([doc for doc in docs if term in doc]), len(docs)) -def inverse_document_frequency(df: int, N: int) -> float: +def inverse_document_frequency(df: int, N: int, smoothing=False) -> float: """ Return an integer denoting the importance of a word. This measure of importance is calculated by log10(N/df), where N is the number of documents and df is the Document Frequency. - @params : df, the Document Frequency, and N, - the number of documents in the corpus. - @returns : log10(N/df) + @params : df, the Document Frequency, N, + the number of documents in the corpus and + smoothing, if True return the idf-smooth + @returns : log10(N/df) or 1+log10(N/1+df) @examples : >>> inverse_document_frequency(3, 0) Traceback (most recent call last): @@ -104,7 +105,14 @@ def inverse_document_frequency(df: int, N: int) -> float: Traceback (most recent call last): ... ZeroDivisionError: df must be > 0 + >>> inverse_document_frequency(0, 3,True) + 1.477 """ + if smoothing: + if N == 0: + raise ValueError("log10(0) is undefined.") + return round(1 + log10(N / (1 + df)), 3) + if df == 0: raise ZeroDivisionError("df must be > 0") elif N == 0: From c38dec091fdea3a2d5ab7b5992fa7c1607b8014d Mon Sep 17 00:00:00 2001 From: mohammadreza490 <47437328+mohammadreza490@users.noreply.github.com> Date: Thu, 3 Sep 2020 15:11:23 +0100 Subject: [PATCH 08/55] capitalize (#2389) * Create capitalize.py This function will capitalize the first character of a sentence or a word * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update strings/capitalize.py Co-authored-by: Christian Clauss * Update capitalize.py * Update strings/capitalize.py Co-authored-by: Christian Clauss * Update capitalize.py * Update capitalize.py * Update capitalize.py * Update strings/capitalize.py Co-authored-by: Christian Clauss * Update capitalize.py * Update strings/capitalize.py Co-authored-by: Christian Clauss * Update capitalize.py * Update capitalize.py Co-authored-by: Christian Clauss --- strings/capitalize.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 strings/capitalize.py diff --git a/strings/capitalize.py b/strings/capitalize.py new file mode 100644 index 000000000000..2a84a325bca4 --- /dev/null +++ b/strings/capitalize.py @@ -0,0 +1,27 @@ +from string import ascii_lowercase, ascii_uppercase + + +def capitalize(sentence: str) -> str: + """ + This function will capitalize the first letter of a sentence or a word + >>> capitalize("hello world") + 'Hello world' + >>> capitalize("123 hello world") + '123 hello world' + >>> capitalize(" hello world") + ' hello world' + >>> capitalize("a") + 'A' + >>> capitalize("") + '' + """ + if not sentence: + return '' + lower_to_upper = {lc: uc for lc, uc in zip(ascii_lowercase, ascii_uppercase)} + return lower_to_upper.get(sentence[0], sentence[0]) + sentence[1:] + + +if __name__ == "__main__": + from doctest import testmod + + testmod() From 1385e47c36f9f5af75c1127bcafe61725a390895 Mon Sep 17 00:00:00 2001 From: mohammadreza490 <47437328+mohammadreza490@users.noreply.github.com> Date: Fri, 4 Sep 2020 14:48:44 +0100 Subject: [PATCH 09/55] Create hexadecimal_to_decimal (#2393) * Create hexadecimal_to_decimal * Update conversions/hexadecimal_to_decimal Co-authored-by: Tapajyoti Bose <44058757+ruppysuppy@users.noreply.github.com> * Update conversions/hexadecimal_to_decimal Co-authored-by: Tapajyoti Bose <44058757+ruppysuppy@users.noreply.github.com> * Update conversions/hexadecimal_to_decimal Co-authored-by: Christian Clauss * Update hexadecimal_to_decimal * Update hexadecimal_to_decimal * Update hexadecimal_to_decimal * Update hexadecimal_to_decimal * Update hexadecimal_to_decimal * Update conversions/hexadecimal_to_decimal Co-authored-by: Christian Clauss * Update hexadecimal_to_decimal Added negative hexadecimal conversion to decimal number * Update hexadecimal_to_decimal * Update conversions/hexadecimal_to_decimal Co-authored-by: Christian Clauss * Update conversions/hexadecimal_to_decimal Co-authored-by: Christian Clauss * Update hexadecimal_to_decimal * Update hexadecimal_to_decimal Co-authored-by: Tapajyoti Bose <44058757+ruppysuppy@users.noreply.github.com> Co-authored-by: Christian Clauss --- conversions/hexadecimal_to_decimal | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 conversions/hexadecimal_to_decimal diff --git a/conversions/hexadecimal_to_decimal b/conversions/hexadecimal_to_decimal new file mode 100644 index 000000000000..e87caa0f4787 --- /dev/null +++ b/conversions/hexadecimal_to_decimal @@ -0,0 +1,45 @@ +hex_table = {hex(i)[2:]: i for i in range(16)} # Use [:2] to strip off the leading '0x' + + +def hex_to_decimal(hex_string: str) -> int: + """ + Convert a hexadecimal value to its decimal equivalent + #https://www.programiz.com/python-programming/methods/built-in/hex + + >>> hex_to_decimal("a") + 10 + >>> hex_to_decimal("12f") + 303 + >>> hex_to_decimal(" 12f ") + 303 + >>> hex_to_decimal("FfFf") + 65535 + >>> hex_to_decimal("-Ff") + -255 + >>> hex_to_decimal("F-f") + ValueError: Non-hexadecimal value was passed to the function + >>> hex_to_decimal("") + ValueError: Empty string value was passed to the function + >>> hex_to_decimal("12m") + ValueError: Non-hexadecimal value was passed to the function + """ + hex_string = hex_string.strip().lower() + if not hex_string: + raise ValueError("Empty string was passed to the function") + is_negative = hex_string[0] == "-" + if is_negative: + hex_string = hex_string[1:] + if not all(char in hex_table for char in hex_string): + raise ValueError("Non-hexadecimal value was passed to the function") + decimal_number = 0 + for char in hex_string: + decimal_number = 16 * decimal_number + hex_table[char] + if is_negative: + decimal_number = -decimal_number + return decimal_number + + +if __name__ == "__main__": + from doctest import testmod + + testmod() From 3b1c4f72cea93803fb8e155b0ae149395426c26f Mon Sep 17 00:00:00 2001 From: NEERAJ ADITYANANTH POLAMPALLI <65017645+NEERAJAP2001@users.noreply.github.com> Date: Sat, 5 Sep 2020 16:39:18 +0530 Subject: [PATCH 10/55] changed a typo (#2396) --- data_structures/linked_list/circular_linked_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/linked_list/circular_linked_list.py b/data_structures/linked_list/circular_linked_list.py index 290e30ebfad6..19d6ee6c6cb3 100644 --- a/data_structures/linked_list/circular_linked_list.py +++ b/data_structures/linked_list/circular_linked_list.py @@ -102,7 +102,7 @@ def append(self, data: Any) -> None: def prepend(self, data: Any) -> None: """ - Adds a ndoe with given data to the front of the CircularLinkedList + Adds a node with given data to the front of the CircularLinkedList >>> cll = CircularLinkedList() >>> cll.prepend(1) >>> cll.prepend(2) From c0dcc556b35093de62a8ed8e3d03f9514f7f3d48 Mon Sep 17 00:00:00 2001 From: NEERAJ ADITYANANTH POLAMPALLI <65017645+NEERAJAP2001@users.noreply.github.com> Date: Sun, 6 Sep 2020 14:10:46 +0530 Subject: [PATCH 11/55] Update triplet_sum.py (#2404) --- other/triplet_sum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/other/triplet_sum.py b/other/triplet_sum.py index a7d6e6331dbc..247e3bb1618d 100644 --- a/other/triplet_sum.py +++ b/other/triplet_sum.py @@ -20,7 +20,7 @@ def make_dataset() -> Tuple[List[int], int]: def triplet_sum1(arr: List[int], target: int) -> Tuple[int, int, int]: """ - Returns a triplet in in array with sum equal to target, + Returns a triplet in the array with sum equal to target, else (0, 0, 0). >>> triplet_sum1([13, 29, 7, 23, 5], 35) (5, 7, 23) @@ -39,7 +39,7 @@ def triplet_sum1(arr: List[int], target: int) -> Tuple[int, int, int]: def triplet_sum2(arr: List[int], target: int) -> Tuple[int, int, int]: """ - Returns a triplet in in array with sum equal to target, + Returns a triplet in the array with sum equal to target, else (0, 0, 0). >>> triplet_sum2([13, 29, 7, 23, 5], 35) (5, 7, 23) From 25946e457080656f2fc23d130e674cccf6a0d0c7 Mon Sep 17 00:00:00 2001 From: Tanuj Dhiman <56601466+tanujdhiman@users.noreply.github.com> Date: Wed, 9 Sep 2020 22:34:46 +0530 Subject: [PATCH 12/55] Update scoring_functions.py (#2291) * Update scoring_functions.py We can find accuracy by manually if we are not going to use sklearn library. * Update scoring_functions.py * Update machine_learning/scoring_functions.py Co-authored-by: Christian Clauss --- machine_learning/scoring_functions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/machine_learning/scoring_functions.py b/machine_learning/scoring_functions.py index a401df139748..08b969a95c3b 100755 --- a/machine_learning/scoring_functions.py +++ b/machine_learning/scoring_functions.py @@ -135,3 +135,7 @@ def mbd(predict, actual): score = float(numerator) / denumerator * 100 return score + + +def manual_accuracy(predict, actual): + return np.mean(np.array(actual) == np.array(predict)) From 4d0a8f235557e46a6b7fac6d4fa5c806788cf360 Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Thu, 10 Sep 2020 16:31:26 +0800 Subject: [PATCH 13/55] Optimized recursive_bubble_sort (#2410) * optimized recursive_bubble_sort * Fixed doctest error due whitespace * reduce loop times for optimization * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- arithmetic_analysis/newton_method.py | 6 +- arithmetic_analysis/newton_raphson.py | 2 +- backtracking/all_permutations.py | 8 +- backtracking/all_subsequences.py | 8 +- backtracking/sudoku.py | 2 +- backtracking/sum_of_subsets.py | 12 +- blockchain/modular_division.py | 10 +- ciphers/enigma_machine2.py | 102 +++-- ciphers/xor_cipher.py | 70 +-- conversions/decimal_to_any.py | 98 ++-- conversions/decimal_to_binary.py | 44 +- conversions/decimal_to_hexadecimal.py | 66 +-- data_structures/binary_tree/avl_tree.py | 2 +- data_structures/binary_tree/red_black_tree.py | 10 +- data_structures/binary_tree/treap.py | 12 +- data_structures/hashing/double_hash.py | 2 +- data_structures/hashing/hash_table.py | 2 +- .../hashing/number_theory/prime_numbers.py | 4 +- data_structures/hashing/quadratic_probing.py | 2 +- data_structures/linked_list/deque_doubly.py | 12 +- .../stacks/infix_to_postfix_conversion.py | 4 +- data_structures/stacks/stack.py | 2 +- digital_image_processing/index_calculation.py | 430 +++++++++--------- divide_and_conquer/closest_pair_of_points.py | 2 +- divide_and_conquer/max_subarray_sum.py | 6 +- .../strassen_matrix_multiplication.py | 4 +- dynamic_programming/rod_cutting.py | 200 ++++---- graphs/bfs_shortest_path.py | 56 +-- graphs/depth_first_search.py | 24 +- graphs/prim.py | 24 +- hashes/md5.py | 4 +- linear_algebra/src/lib.py | 130 +++--- linear_algebra/src/test_linear_algebra.py | 26 +- machine_learning/decision_tree.py | 3 +- machine_learning/k_means_clust.py | 12 +- .../linear_discriminant_analysis.py | 2 +- machine_learning/linear_regression.py | 8 +- maths/kth_lexicographic_permutation.py | 26 +- maths/newton_raphson.py | 4 +- maths/prime_sieve_eratosthenes.py | 9 +- maths/relu.py | 20 +- maths/softmax.py | 32 +- maths/sum_of_geometric_progression.py | 2 +- maths/zellers_congruence.py | 3 +- matrix/matrix_operation.py | 4 +- other/activity_selection.py | 21 +- other/game_of_life.py | 2 +- other/least_recently_used.py | 10 +- other/magicdiamondpattern.py | 6 +- other/primelib.py | 92 ++-- project_euler/problem_09/sol2.py | 3 +- project_euler/problem_10/sol3.py | 2 +- project_euler/problem_15/sol1.py | 50 +- project_euler/problem_27/problem_27_sol1.py | 22 +- project_euler/problem_56/sol1.py | 22 +- sorts/merge_sort.py | 3 + sorts/recursive_bubble_sort.py | 41 +- strings/boyer_moore_search.py | 2 +- strings/capitalize.py | 2 +- traversals/binary_tree_traversals.py | 38 +- 60 files changed, 934 insertions(+), 893 deletions(-) diff --git a/arithmetic_analysis/newton_method.py b/arithmetic_analysis/newton_method.py index 542f994aaf19..97d5d3d3e470 100644 --- a/arithmetic_analysis/newton_method.py +++ b/arithmetic_analysis/newton_method.py @@ -7,7 +7,11 @@ # function is the f(x) and derivative is the f'(x) -def newton(function: RealFunc, derivative: RealFunc, starting_int: int,) -> float: +def newton( + function: RealFunc, + derivative: RealFunc, + starting_int: int, +) -> float: """ >>> newton(lambda x: x ** 3 - 2 * x - 5, lambda x: 3 * x ** 2 - 2, 3) 2.0945514815423474 diff --git a/arithmetic_analysis/newton_raphson.py b/arithmetic_analysis/newton_raphson.py index 890cff060ec8..948759a09a2a 100644 --- a/arithmetic_analysis/newton_raphson.py +++ b/arithmetic_analysis/newton_raphson.py @@ -9,7 +9,7 @@ def newton_raphson(func: str, a: int, precision: int = 10 ** -10) -> float: - """ Finds root from the point 'a' onwards by Newton-Raphson method + """Finds root from the point 'a' onwards by Newton-Raphson method >>> newton_raphson("sin(x)", 2) 3.1415926536808043 >>> newton_raphson("x**2 - 5*x +2", 0.4) diff --git a/backtracking/all_permutations.py b/backtracking/all_permutations.py index d144436033de..5244fef97f93 100644 --- a/backtracking/all_permutations.py +++ b/backtracking/all_permutations.py @@ -13,10 +13,10 @@ def generate_all_permutations(sequence): def create_state_space_tree(sequence, current_sequence, index, index_used): """ - Creates a state space tree to iterate through each branch using DFS. - We know that each state has exactly len(sequence) - index children. - It terminates when it reaches the end of the given sequence. - """ + Creates a state space tree to iterate through each branch using DFS. + We know that each state has exactly len(sequence) - index children. + It terminates when it reaches the end of the given sequence. + """ if index == len(sequence): print(current_sequence) diff --git a/backtracking/all_subsequences.py b/backtracking/all_subsequences.py index 8283386991d9..3851c4ab0118 100644 --- a/backtracking/all_subsequences.py +++ b/backtracking/all_subsequences.py @@ -13,10 +13,10 @@ def generate_all_subsequences(sequence): def create_state_space_tree(sequence, current_subsequence, index): """ - Creates a state space tree to iterate through each branch using DFS. - We know that each state has exactly two children. - It terminates when it reaches the end of the given sequence. - """ + Creates a state space tree to iterate through each branch using DFS. + We know that each state has exactly two children. + It terminates when it reaches the end of the given sequence. + """ if index == len(sequence): print(current_subsequence) diff --git a/backtracking/sudoku.py b/backtracking/sudoku.py index d864e2823a9b..b3d38b4cc7c7 100644 --- a/backtracking/sudoku.py +++ b/backtracking/sudoku.py @@ -105,7 +105,7 @@ def sudoku(grid): [7, 4, 5, 2, 8, 6, 3, 1, 9]] >>> sudoku(no_solution) False - """ + """ if is_completed(grid): return grid diff --git a/backtracking/sum_of_subsets.py b/backtracking/sum_of_subsets.py index c03df18ae743..425ddcff927e 100644 --- a/backtracking/sum_of_subsets.py +++ b/backtracking/sum_of_subsets.py @@ -19,13 +19,13 @@ def generate_sum_of_subsets_soln(nums, max_sum): def create_state_space_tree(nums, max_sum, num_index, path, result, remaining_nums_sum): """ - Creates a state space tree to iterate through each branch using DFS. - It terminates the branching of a node when any of the two conditions - given below satisfy. - This algorithm follows depth-fist-search and backtracks when the node is not - branchable. + Creates a state space tree to iterate through each branch using DFS. + It terminates the branching of a node when any of the two conditions + given below satisfy. + This algorithm follows depth-fist-search and backtracks when the node is not + branchable. - """ + """ if sum(path) > max_sum or (remaining_nums_sum + sum(path)) < max_sum: return if sum(path) == max_sum: diff --git a/blockchain/modular_division.py b/blockchain/modular_division.py index c09863a3c5f0..8fcf6e37cbed 100644 --- a/blockchain/modular_division.py +++ b/blockchain/modular_division.py @@ -74,13 +74,13 @@ def modular_division2(a, b, n): def extended_gcd(a, b): """ - >>> extended_gcd(10, 6) - (2, -1, 2) + >>> extended_gcd(10, 6) + (2, -1, 2) - >>> extended_gcd(7, 5) - (1, -2, 3) + >>> extended_gcd(7, 5) + (1, -2, 3) - ** extended_gcd function is used when d = gcd(a,b) is required in output + ** extended_gcd function is used when d = gcd(a,b) is required in output """ assert a >= 0 and b >= 0 diff --git a/ciphers/enigma_machine2.py b/ciphers/enigma_machine2.py index 4c79e1c2fab9..0fbe97284d38 100644 --- a/ciphers/enigma_machine2.py +++ b/ciphers/enigma_machine2.py @@ -17,26 +17,50 @@ # used alphabet -------------------------- # from string.ascii_uppercase -abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" # -------------------------- default selection -------------------------- # rotors -------------------------- -rotor1 = 'EGZWVONAHDCLFQMSIPJBYUKXTR' -rotor2 = 'FOBHMDKEXQNRAULPGSJVTYICZW' -rotor3 = 'ZJXESIUQLHAVRMDOYGTNFWPBKC' +rotor1 = "EGZWVONAHDCLFQMSIPJBYUKXTR" +rotor2 = "FOBHMDKEXQNRAULPGSJVTYICZW" +rotor3 = "ZJXESIUQLHAVRMDOYGTNFWPBKC" # reflector -------------------------- -reflector = {'A': 'N', 'N': 'A', 'B': 'O', 'O': 'B', 'C': 'P', 'P': 'C', 'D': 'Q', - 'Q': 'D', 'E': 'R', 'R': 'E', 'F': 'S', 'S': 'F', 'G': 'T', 'T': 'G', - 'H': 'U', 'U': 'H', 'I': 'V', 'V': 'I', 'J': 'W', 'W': 'J', 'K': 'X', - 'X': 'K', 'L': 'Y', 'Y': 'L', 'M': 'Z', 'Z': 'M'} +reflector = { + "A": "N", + "N": "A", + "B": "O", + "O": "B", + "C": "P", + "P": "C", + "D": "Q", + "Q": "D", + "E": "R", + "R": "E", + "F": "S", + "S": "F", + "G": "T", + "T": "G", + "H": "U", + "U": "H", + "I": "V", + "V": "I", + "J": "W", + "W": "J", + "K": "X", + "X": "K", + "L": "Y", + "Y": "L", + "M": "Z", + "Z": "M", +} # -------------------------- extra rotors -------------------------- -rotor4 = 'RMDJXFUWGISLHVTCQNKYPBEZOA' -rotor5 = 'SGLCPQWZHKXAREONTFBVIYJUDM' -rotor6 = 'HVSICLTYKQUBXDWAJZOMFGPREN' -rotor7 = 'RZWQHFMVDBKICJLNTUXAGYPSOE' -rotor8 = 'LFKIJODBEGAMQPXVUHYSTCZRWN' -rotor9 = 'KOAEGVDHXPQZMLFTYWJNBRCIUS' +rotor4 = "RMDJXFUWGISLHVTCQNKYPBEZOA" +rotor5 = "SGLCPQWZHKXAREONTFBVIYJUDM" +rotor6 = "HVSICLTYKQUBXDWAJZOMFGPREN" +rotor7 = "RZWQHFMVDBKICJLNTUXAGYPSOE" +rotor8 = "LFKIJODBEGAMQPXVUHYSTCZRWN" +rotor9 = "KOAEGVDHXPQZMLFTYWJNBRCIUS" def _validator(rotpos: tuple, rotsel: tuple, pb: str) -> tuple: @@ -57,19 +81,22 @@ def _validator(rotpos: tuple, rotsel: tuple, pb: str) -> tuple: unique_rotsel = len(set(rotsel)) if unique_rotsel < 3: - raise Exception(f'Please use 3 unique rotors (not {unique_rotsel})') + raise Exception(f"Please use 3 unique rotors (not {unique_rotsel})") # Checks if rotor positions are valid rotorpos1, rotorpos2, rotorpos3 = rotpos if not 0 < rotorpos1 <= len(abc): - raise ValueError(f'First rotor position is not within range of 1..26 (' - f'{rotorpos1}') + raise ValueError( + f"First rotor position is not within range of 1..26 (" f"{rotorpos1}" + ) if not 0 < rotorpos2 <= len(abc): - raise ValueError(f'Second rotor position is not within range of 1..26 (' - f'{rotorpos2})') + raise ValueError( + f"Second rotor position is not within range of 1..26 (" f"{rotorpos2})" + ) if not 0 < rotorpos3 <= len(abc): - raise ValueError(f'Third rotor position is not within range of 1..26 (' - f'{rotorpos3})') + raise ValueError( + f"Third rotor position is not within range of 1..26 (" f"{rotorpos3})" + ) # Validates string and returns dict pb = _plugboard(pb) @@ -97,21 +124,21 @@ def _plugboard(pbstring: str) -> dict: # a) is type string # b) has even length (so pairs can be made) if not isinstance(pbstring, str): - raise TypeError(f'Plugboard setting isn\'t type string ({type(pbstring)})') + raise TypeError(f"Plugboard setting isn't type string ({type(pbstring)})") elif len(pbstring) % 2 != 0: - raise Exception(f'Odd number of symbols ({len(pbstring)})') - elif pbstring == '': + raise Exception(f"Odd number of symbols ({len(pbstring)})") + elif pbstring == "": return {} - pbstring.replace(' ', '') + pbstring.replace(" ", "") # Checks if all characters are unique tmppbl = set() for i in pbstring: if i not in abc: - raise Exception(f'\'{i}\' not in list of symbols') + raise Exception(f"'{i}' not in list of symbols") elif i in tmppbl: - raise Exception(f'Duplicate symbol ({i})') + raise Exception(f"Duplicate symbol ({i})") else: tmppbl.add(i) del tmppbl @@ -125,8 +152,12 @@ def _plugboard(pbstring: str) -> dict: return pb -def enigma(text: str, rotor_position: tuple, - rotor_selection: tuple = (rotor1, rotor2, rotor3), plugb: str = '') -> str: +def enigma( + text: str, + rotor_position: tuple, + rotor_selection: tuple = (rotor1, rotor2, rotor3), + plugb: str = "", +) -> str: """ The only difference with real-world enigma is that I allowed string input. All characters are converted to uppercase. (non-letter symbol are ignored) @@ -179,7 +210,8 @@ def enigma(text: str, rotor_position: tuple, text = text.upper() rotor_position, rotor_selection, plugboard = _validator( - rotor_position, rotor_selection, plugb.upper()) + rotor_position, rotor_selection, plugb.upper() + ) rotorpos1, rotorpos2, rotorpos3 = rotor_position rotor1, rotor2, rotor3 = rotor_selection @@ -245,12 +277,12 @@ def enigma(text: str, rotor_position: tuple, return "".join(result) -if __name__ == '__main__': - message = 'This is my Python script that emulates the Enigma machine from WWII.' +if __name__ == "__main__": + message = "This is my Python script that emulates the Enigma machine from WWII." rotor_pos = (1, 1, 1) - pb = 'pictures' + pb = "pictures" rotor_sel = (rotor2, rotor4, rotor8) en = enigma(message, rotor_pos, rotor_sel, pb) - print('Encrypted message:', en) - print('Decrypted message:', enigma(en, rotor_pos, rotor_sel, pb)) + print("Encrypted message:", en) + print("Decrypted message:", enigma(en, rotor_pos, rotor_sel, pb)) diff --git a/ciphers/xor_cipher.py b/ciphers/xor_cipher.py index 0fcfbb0b9ae2..3b045fdac64a 100644 --- a/ciphers/xor_cipher.py +++ b/ciphers/xor_cipher.py @@ -21,20 +21,20 @@ class XORCipher: def __init__(self, key=0): """ - simple constructor that receives a key or uses - default key = 0 - """ + simple constructor that receives a key or uses + default key = 0 + """ # private field self.__key = key def encrypt(self, content, key): """ - input: 'content' of type string and 'key' of type int - output: encrypted string 'content' as a list of chars - if key not passed the method uses the key by the constructor. - otherwise key = 1 - """ + input: 'content' of type string and 'key' of type int + output: encrypted string 'content' as a list of chars + if key not passed the method uses the key by the constructor. + otherwise key = 1 + """ # precondition assert isinstance(key, int) and isinstance(content, str) @@ -55,11 +55,11 @@ def encrypt(self, content, key): def decrypt(self, content, key): """ - input: 'content' of type list and 'key' of type int - output: decrypted string 'content' as a list of chars - if key not passed the method uses the key by the constructor. - otherwise key = 1 - """ + input: 'content' of type list and 'key' of type int + output: decrypted string 'content' as a list of chars + if key not passed the method uses the key by the constructor. + otherwise key = 1 + """ # precondition assert isinstance(key, int) and isinstance(content, list) @@ -80,11 +80,11 @@ def decrypt(self, content, key): def encrypt_string(self, content, key=0): """ - input: 'content' of type string and 'key' of type int - output: encrypted string 'content' - if key not passed the method uses the key by the constructor. - otherwise key = 1 - """ + input: 'content' of type string and 'key' of type int + output: encrypted string 'content' + if key not passed the method uses the key by the constructor. + otherwise key = 1 + """ # precondition assert isinstance(key, int) and isinstance(content, str) @@ -105,11 +105,11 @@ def encrypt_string(self, content, key=0): def decrypt_string(self, content, key=0): """ - input: 'content' of type string and 'key' of type int - output: decrypted string 'content' - if key not passed the method uses the key by the constructor. - otherwise key = 1 - """ + input: 'content' of type string and 'key' of type int + output: decrypted string 'content' + if key not passed the method uses the key by the constructor. + otherwise key = 1 + """ # precondition assert isinstance(key, int) and isinstance(content, str) @@ -130,12 +130,12 @@ def decrypt_string(self, content, key=0): def encrypt_file(self, file, key=0): """ - input: filename (str) and a key (int) - output: returns true if encrypt process was - successful otherwise false - if key not passed the method uses the key by the constructor. - otherwise key = 1 - """ + input: filename (str) and a key (int) + output: returns true if encrypt process was + successful otherwise false + if key not passed the method uses the key by the constructor. + otherwise key = 1 + """ # precondition assert isinstance(file, str) and isinstance(key, int) @@ -155,12 +155,12 @@ def encrypt_file(self, file, key=0): def decrypt_file(self, file, key): """ - input: filename (str) and a key (int) - output: returns true if decrypt process was - successful otherwise false - if key not passed the method uses the key by the constructor. - otherwise key = 1 - """ + input: filename (str) and a key (int) + output: returns true if decrypt process was + successful otherwise false + if key not passed the method uses the key by the constructor. + otherwise key = 1 + """ # precondition assert isinstance(file, str) and isinstance(key, int) diff --git a/conversions/decimal_to_any.py b/conversions/decimal_to_any.py index cbed1ac12214..3c72a7732ac6 100644 --- a/conversions/decimal_to_any.py +++ b/conversions/decimal_to_any.py @@ -3,55 +3,55 @@ def decimal_to_any(num: int, base: int) -> str: """ - Convert a positive integer to another base as str. - >>> decimal_to_any(0, 2) - '0' - >>> decimal_to_any(5, 4) - '11' - >>> decimal_to_any(20, 3) - '202' - >>> decimal_to_any(58, 16) - '3A' - >>> decimal_to_any(243, 17) - 'E5' - >>> decimal_to_any(34923, 36) - 'QY3' - >>> decimal_to_any(10, 11) - 'A' - >>> decimal_to_any(16, 16) - '10' - >>> decimal_to_any(36, 36) - '10' - >>> # negatives will error - >>> decimal_to_any(-45, 8) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: parameter must be positive int - >>> # floats will error - >>> decimal_to_any(34.4, 6) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: int() can't convert non-string with explicit base - >>> # a float base will error - >>> decimal_to_any(5, 2.5) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: 'float' object cannot be interpreted as an integer - >>> # a str base will error - >>> decimal_to_any(10, '16') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: 'str' object cannot be interpreted as an integer - >>> # a base less than 2 will error - >>> decimal_to_any(7, 0) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: base must be >= 2 - >>> # a base greater than 36 will error - >>> decimal_to_any(34, 37) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: base must be <= 36 + Convert a positive integer to another base as str. + >>> decimal_to_any(0, 2) + '0' + >>> decimal_to_any(5, 4) + '11' + >>> decimal_to_any(20, 3) + '202' + >>> decimal_to_any(58, 16) + '3A' + >>> decimal_to_any(243, 17) + 'E5' + >>> decimal_to_any(34923, 36) + 'QY3' + >>> decimal_to_any(10, 11) + 'A' + >>> decimal_to_any(16, 16) + '10' + >>> decimal_to_any(36, 36) + '10' + >>> # negatives will error + >>> decimal_to_any(-45, 8) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: parameter must be positive int + >>> # floats will error + >>> decimal_to_any(34.4, 6) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: int() can't convert non-string with explicit base + >>> # a float base will error + >>> decimal_to_any(5, 2.5) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: 'float' object cannot be interpreted as an integer + >>> # a str base will error + >>> decimal_to_any(10, '16') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: 'str' object cannot be interpreted as an integer + >>> # a base less than 2 will error + >>> decimal_to_any(7, 0) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: base must be >= 2 + >>> # a base greater than 36 will error + >>> decimal_to_any(34, 37) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: base must be <= 36 """ if isinstance(num, float): raise TypeError("int() can't convert non-string with explicit base") diff --git a/conversions/decimal_to_binary.py b/conversions/decimal_to_binary.py index 8fcf226c346c..7e83aee4f7a5 100644 --- a/conversions/decimal_to_binary.py +++ b/conversions/decimal_to_binary.py @@ -4,28 +4,28 @@ def decimal_to_binary(num: int) -> str: """ - Convert an Integer Decimal Number to a Binary Number as str. - >>> decimal_to_binary(0) - '0b0' - >>> decimal_to_binary(2) - '0b10' - >>> decimal_to_binary(7) - '0b111' - >>> decimal_to_binary(35) - '0b100011' - >>> # negatives work too - >>> decimal_to_binary(-2) - '-0b10' - >>> # other floats will error - >>> decimal_to_binary(16.16) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: 'float' object cannot be interpreted as an integer - >>> # strings will error as well - >>> decimal_to_binary('0xfffff') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - TypeError: 'str' object cannot be interpreted as an integer + Convert an Integer Decimal Number to a Binary Number as str. + >>> decimal_to_binary(0) + '0b0' + >>> decimal_to_binary(2) + '0b10' + >>> decimal_to_binary(7) + '0b111' + >>> decimal_to_binary(35) + '0b100011' + >>> # negatives work too + >>> decimal_to_binary(-2) + '-0b10' + >>> # other floats will error + >>> decimal_to_binary(16.16) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: 'float' object cannot be interpreted as an integer + >>> # strings will error as well + >>> decimal_to_binary('0xfffff') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: 'str' object cannot be interpreted as an integer """ if type(num) == float: diff --git a/conversions/decimal_to_hexadecimal.py b/conversions/decimal_to_hexadecimal.py index 6bd9533ab390..433f78dfecb7 100644 --- a/conversions/decimal_to_hexadecimal.py +++ b/conversions/decimal_to_hexadecimal.py @@ -23,39 +23,39 @@ def decimal_to_hexadecimal(decimal): """ - take integer decimal value, return hexadecimal representation as str beginning - with 0x - >>> decimal_to_hexadecimal(5) - '0x5' - >>> decimal_to_hexadecimal(15) - '0xf' - >>> decimal_to_hexadecimal(37) - '0x25' - >>> decimal_to_hexadecimal(255) - '0xff' - >>> decimal_to_hexadecimal(4096) - '0x1000' - >>> decimal_to_hexadecimal(999098) - '0xf3eba' - >>> # negatives work too - >>> decimal_to_hexadecimal(-256) - '-0x100' - >>> # floats are acceptable if equivalent to an int - >>> decimal_to_hexadecimal(17.0) - '0x11' - >>> # other floats will error - >>> decimal_to_hexadecimal(16.16) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - AssertionError - >>> # strings will error as well - >>> decimal_to_hexadecimal('0xfffff') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - AssertionError - >>> # results are the same when compared to Python's default hex function - >>> decimal_to_hexadecimal(-256) == hex(-256) - True + take integer decimal value, return hexadecimal representation as str beginning + with 0x + >>> decimal_to_hexadecimal(5) + '0x5' + >>> decimal_to_hexadecimal(15) + '0xf' + >>> decimal_to_hexadecimal(37) + '0x25' + >>> decimal_to_hexadecimal(255) + '0xff' + >>> decimal_to_hexadecimal(4096) + '0x1000' + >>> decimal_to_hexadecimal(999098) + '0xf3eba' + >>> # negatives work too + >>> decimal_to_hexadecimal(-256) + '-0x100' + >>> # floats are acceptable if equivalent to an int + >>> decimal_to_hexadecimal(17.0) + '0x11' + >>> # other floats will error + >>> decimal_to_hexadecimal(16.16) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + AssertionError + >>> # strings will error as well + >>> decimal_to_hexadecimal('0xfffff') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + AssertionError + >>> # results are the same when compared to Python's default hex function + >>> decimal_to_hexadecimal(-256) == hex(-256) + True """ assert type(decimal) in (int, float) and decimal == int(decimal) hexadecimal = "" diff --git a/data_structures/binary_tree/avl_tree.py b/data_structures/binary_tree/avl_tree.py index c6a45f1cbeb7..3362610b9303 100644 --- a/data_structures/binary_tree/avl_tree.py +++ b/data_structures/binary_tree/avl_tree.py @@ -109,7 +109,7 @@ def right_rotation(node): def left_rotation(node): """ - a mirror symmetry rotation of the left_rotation + a mirror symmetry rotation of the left_rotation """ print("right rotation node:", node.get_data()) ret = node.get_right() diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 379cee61d888..5d721edfa45b 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -28,11 +28,11 @@ def __init__( right: Optional["RedBlackTree"] = None, ) -> None: """Initialize a new Red-Black Tree node with the given values: - label: The value associated with this node - color: 0 if black, 1 if red - parent: The parent to this node - left: This node's left child - right: This node's right child + label: The value associated with this node + color: 0 if black, 1 if red + parent: The parent to this node + left: This node's left child + right: This node's right child """ self.label = label self.parent = parent diff --git a/data_structures/binary_tree/treap.py b/data_structures/binary_tree/treap.py index 52b757d584c3..fbb57650280e 100644 --- a/data_structures/binary_tree/treap.py +++ b/data_structures/binary_tree/treap.py @@ -118,7 +118,7 @@ def inorder(root: Node): return else: inorder(root.left) - print(root.value, end=" ") + print(root.value, end=",") inorder(root.right) @@ -130,19 +130,19 @@ def interactTreap(root, args): >>> root = interactTreap(None, "+1") >>> inorder(root) - 1 + 1, >>> root = interactTreap(root, "+3 +5 +17 +19 +2 +16 +4 +0") >>> inorder(root) - 0 1 2 3 4 5 16 17 19 + 0,1,2,3,4,5,16,17,19, >>> root = interactTreap(root, "+4 +4 +4") >>> inorder(root) - 0 1 2 3 4 4 4 4 5 16 17 19 + 0,1,2,3,4,4,4,4,5,16,17,19, >>> root = interactTreap(root, "-0") >>> inorder(root) - 1 2 3 4 4 4 4 5 16 17 19 + 1,2,3,4,4,4,4,5,16,17,19, >>> root = interactTreap(root, "-4") >>> inorder(root) - 1 2 3 5 16 17 19 + 1,2,3,5,16,17,19, >>> root = interactTreap(root, "=0") Unknown command """ diff --git a/data_structures/hashing/double_hash.py b/data_structures/hashing/double_hash.py index 9c6c8fed6a00..1007849c5a53 100644 --- a/data_structures/hashing/double_hash.py +++ b/data_structures/hashing/double_hash.py @@ -5,7 +5,7 @@ class DoubleHash(HashTable): """ - Hash Table example with open addressing and Double Hash + Hash Table example with open addressing and Double Hash """ def __init__(self, *args, **kwargs): diff --git a/data_structures/hashing/hash_table.py b/data_structures/hashing/hash_table.py index 3b39742f9d09..6e03be95b737 100644 --- a/data_structures/hashing/hash_table.py +++ b/data_structures/hashing/hash_table.py @@ -4,7 +4,7 @@ class HashTable: """ - Basic Hash Table example with open addressing and linear probing + Basic Hash Table example with open addressing and linear probing """ def __init__(self, size_table, charge_factor=None, lim_charge=None): diff --git a/data_structures/hashing/number_theory/prime_numbers.py b/data_structures/hashing/number_theory/prime_numbers.py index 2a966e0da7f2..db4d40f475b2 100644 --- a/data_structures/hashing/number_theory/prime_numbers.py +++ b/data_structures/hashing/number_theory/prime_numbers.py @@ -6,8 +6,8 @@ def check_prime(number): """ - it's not the best solution - """ + it's not the best solution + """ special_non_primes = [0, 1, 2] if number in special_non_primes[:2]: return 2 diff --git a/data_structures/hashing/quadratic_probing.py b/data_structures/hashing/quadratic_probing.py index 668ddaa85048..06f3ced49d3c 100644 --- a/data_structures/hashing/quadratic_probing.py +++ b/data_structures/hashing/quadratic_probing.py @@ -5,7 +5,7 @@ class QuadraticProbing(HashTable): """ - Basic Hash Table example with open addressing using Quadratic Probing + Basic Hash Table example with open addressing using Quadratic Probing """ def __init__(self, *args, **kwargs): diff --git a/data_structures/linked_list/deque_doubly.py b/data_structures/linked_list/deque_doubly.py index 7025a7ea22f9..c6ee2ed27ba5 100644 --- a/data_structures/linked_list/deque_doubly.py +++ b/data_structures/linked_list/deque_doubly.py @@ -61,7 +61,7 @@ def _delete(self, node): class LinkedDeque(_DoublyLinkedBase): def first(self): - """ return first element + """return first element >>> d = LinkedDeque() >>> d.add_first('A').first() 'A' @@ -73,7 +73,7 @@ def first(self): return self._header._next._data def last(self): - """ return last element + """return last element >>> d = LinkedDeque() >>> d.add_last('A').last() 'A' @@ -87,14 +87,14 @@ def last(self): # DEque Insert Operations (At the front, At the end) def add_first(self, element): - """ insertion in the front + """insertion in the front >>> LinkedDeque().add_first('AV').first() 'AV' """ return self._insert(self._header, element, self._header._next) def add_last(self, element): - """ insertion in the end + """insertion in the end >>> LinkedDeque().add_last('B').last() 'B' """ @@ -103,7 +103,7 @@ def add_last(self, element): # DEqueu Remove Operations (At the front, At the end) def remove_first(self): - """ removal from the front + """removal from the front >>> d = LinkedDeque() >>> d.is_empty() True @@ -123,7 +123,7 @@ def remove_first(self): return self._delete(self._header._next) def remove_last(self): - """ removal in the end + """removal in the end >>> d = LinkedDeque() >>> d.is_empty() True diff --git a/data_structures/stacks/infix_to_postfix_conversion.py b/data_structures/stacks/infix_to_postfix_conversion.py index 61114402377a..4a1180c9d8e4 100644 --- a/data_structures/stacks/infix_to_postfix_conversion.py +++ b/data_structures/stacks/infix_to_postfix_conversion.py @@ -10,7 +10,7 @@ def is_operand(char): def precedence(char): - """ Return integer value representing an operator's precedence, or + """Return integer value representing an operator's precedence, or order of operation. https://en.wikipedia.org/wiki/Order_of_operations @@ -20,7 +20,7 @@ def precedence(char): def infix_to_postfix(expression): - """ Convert infix notation to postfix notation using the Shunting-yard + """Convert infix notation to postfix notation using the Shunting-yard algorithm. https://en.wikipedia.org/wiki/Shunting-yard_algorithm diff --git a/data_structures/stacks/stack.py b/data_structures/stacks/stack.py index baa0857eec0a..a4bcb5beabd4 100644 --- a/data_structures/stacks/stack.py +++ b/data_structures/stacks/stack.py @@ -2,7 +2,7 @@ class Stack: - """ A stack is an abstract data type that serves as a collection of + """A stack is an abstract data type that serves as a collection of elements with two principal operations: push() and pop(). push() adds an element to the top of the stack, and pop() removes an element from the top of a stack. The order in which elements come off of a stack are diff --git a/digital_image_processing/index_calculation.py b/digital_image_processing/index_calculation.py index d55815a6e15e..4350b8603390 100644 --- a/digital_image_processing/index_calculation.py +++ b/digital_image_processing/index_calculation.py @@ -10,98 +10,98 @@ # Class implemented to calculus the index class IndexCalculation: """ - # Class Summary - This algorithm consists in calculating vegetation indices, these - indices can be used for precision agriculture for example (or remote - sensing). There are functions to define the data and to calculate the - implemented indices. - - # Vegetation index - https://en.wikipedia.org/wiki/Vegetation_Index - A Vegetation Index (VI) is a spectral transformation of two or more bands - designed to enhance the contribution of vegetation properties and allow - reliable spatial and temporal inter-comparisons of terrestrial - photosynthetic activity and canopy structural variations - - # Information about channels (Wavelength range for each) - * nir - near-infrared - https://www.malvernpanalytical.com/br/products/technology/near-infrared-spectroscopy - Wavelength Range 700 nm to 2500 nm - * Red Edge - https://en.wikipedia.org/wiki/Red_edge - Wavelength Range 680 nm to 730 nm - * red - https://en.wikipedia.org/wiki/Color - Wavelength Range 635 nm to 700 nm - * blue - https://en.wikipedia.org/wiki/Color - Wavelength Range 450 nm to 490 nm - * green - https://en.wikipedia.org/wiki/Color - Wavelength Range 520 nm to 560 nm - - - # Implemented index list - #"abbreviationOfIndexName" -- list of channels used - - #"ARVI2" -- red, nir - #"CCCI" -- red, redEdge, nir - #"CVI" -- red, green, nir - #"GLI" -- red, green, blue - #"NDVI" -- red, nir - #"BNDVI" -- blue, nir - #"redEdgeNDVI" -- red, redEdge - #"GNDVI" -- green, nir - #"GBNDVI" -- green, blue, nir - #"GRNDVI" -- red, green, nir - #"RBNDVI" -- red, blue, nir - #"PNDVI" -- red, green, blue, nir - #"ATSAVI" -- red, nir - #"BWDRVI" -- blue, nir - #"CIgreen" -- green, nir - #"CIrededge" -- redEdge, nir - #"CI" -- red, blue - #"CTVI" -- red, nir - #"GDVI" -- green, nir - #"EVI" -- red, blue, nir - #"GEMI" -- red, nir - #"GOSAVI" -- green, nir - #"GSAVI" -- green, nir - #"Hue" -- red, green, blue - #"IVI" -- red, nir - #"IPVI" -- red, nir - #"I" -- red, green, blue - #"RVI" -- red, nir - #"MRVI" -- red, nir - #"MSAVI" -- red, nir - #"NormG" -- red, green, nir - #"NormNIR" -- red, green, nir - #"NormR" -- red, green, nir - #"NGRDI" -- red, green - #"RI" -- red, green - #"S" -- red, green, blue - #"IF" -- red, green, blue - #"DVI" -- red, nir - #"TVI" -- red, nir - #"NDRE" -- redEdge, nir - - #list of all index implemented - #allIndex = ["ARVI2", "CCCI", "CVI", "GLI", "NDVI", "BNDVI", "redEdgeNDVI", - "GNDVI", "GBNDVI", "GRNDVI", "RBNDVI", "PNDVI", "ATSAVI", - "BWDRVI", "CIgreen", "CIrededge", "CI", "CTVI", "GDVI", "EVI", - "GEMI", "GOSAVI", "GSAVI", "Hue", "IVI", "IPVI", "I", "RVI", - "MRVI", "MSAVI", "NormG", "NormNIR", "NormR", "NGRDI", "RI", - "S", "IF", "DVI", "TVI", "NDRE"] - - #list of index with not blue channel - #notBlueIndex = ["ARVI2", "CCCI", "CVI", "NDVI", "redEdgeNDVI", "GNDVI", - "GRNDVI", "ATSAVI", "CIgreen", "CIrededge", "CTVI", "GDVI", - "GEMI", "GOSAVI", "GSAVI", "IVI", "IPVI", "RVI", "MRVI", - "MSAVI", "NormG", "NormNIR", "NormR", "NGRDI", "RI", "DVI", - "TVI", "NDRE"] - - #list of index just with RGB channels - #RGBIndex = ["GLI", "CI", "Hue", "I", "NGRDI", "RI", "S", "IF"] + # Class Summary + This algorithm consists in calculating vegetation indices, these + indices can be used for precision agriculture for example (or remote + sensing). There are functions to define the data and to calculate the + implemented indices. + + # Vegetation index + https://en.wikipedia.org/wiki/Vegetation_Index + A Vegetation Index (VI) is a spectral transformation of two or more bands + designed to enhance the contribution of vegetation properties and allow + reliable spatial and temporal inter-comparisons of terrestrial + photosynthetic activity and canopy structural variations + + # Information about channels (Wavelength range for each) + * nir - near-infrared + https://www.malvernpanalytical.com/br/products/technology/near-infrared-spectroscopy + Wavelength Range 700 nm to 2500 nm + * Red Edge + https://en.wikipedia.org/wiki/Red_edge + Wavelength Range 680 nm to 730 nm + * red + https://en.wikipedia.org/wiki/Color + Wavelength Range 635 nm to 700 nm + * blue + https://en.wikipedia.org/wiki/Color + Wavelength Range 450 nm to 490 nm + * green + https://en.wikipedia.org/wiki/Color + Wavelength Range 520 nm to 560 nm + + + # Implemented index list + #"abbreviationOfIndexName" -- list of channels used + + #"ARVI2" -- red, nir + #"CCCI" -- red, redEdge, nir + #"CVI" -- red, green, nir + #"GLI" -- red, green, blue + #"NDVI" -- red, nir + #"BNDVI" -- blue, nir + #"redEdgeNDVI" -- red, redEdge + #"GNDVI" -- green, nir + #"GBNDVI" -- green, blue, nir + #"GRNDVI" -- red, green, nir + #"RBNDVI" -- red, blue, nir + #"PNDVI" -- red, green, blue, nir + #"ATSAVI" -- red, nir + #"BWDRVI" -- blue, nir + #"CIgreen" -- green, nir + #"CIrededge" -- redEdge, nir + #"CI" -- red, blue + #"CTVI" -- red, nir + #"GDVI" -- green, nir + #"EVI" -- red, blue, nir + #"GEMI" -- red, nir + #"GOSAVI" -- green, nir + #"GSAVI" -- green, nir + #"Hue" -- red, green, blue + #"IVI" -- red, nir + #"IPVI" -- red, nir + #"I" -- red, green, blue + #"RVI" -- red, nir + #"MRVI" -- red, nir + #"MSAVI" -- red, nir + #"NormG" -- red, green, nir + #"NormNIR" -- red, green, nir + #"NormR" -- red, green, nir + #"NGRDI" -- red, green + #"RI" -- red, green + #"S" -- red, green, blue + #"IF" -- red, green, blue + #"DVI" -- red, nir + #"TVI" -- red, nir + #"NDRE" -- redEdge, nir + + #list of all index implemented + #allIndex = ["ARVI2", "CCCI", "CVI", "GLI", "NDVI", "BNDVI", "redEdgeNDVI", + "GNDVI", "GBNDVI", "GRNDVI", "RBNDVI", "PNDVI", "ATSAVI", + "BWDRVI", "CIgreen", "CIrededge", "CI", "CTVI", "GDVI", "EVI", + "GEMI", "GOSAVI", "GSAVI", "Hue", "IVI", "IPVI", "I", "RVI", + "MRVI", "MSAVI", "NormG", "NormNIR", "NormR", "NGRDI", "RI", + "S", "IF", "DVI", "TVI", "NDRE"] + + #list of index with not blue channel + #notBlueIndex = ["ARVI2", "CCCI", "CVI", "NDVI", "redEdgeNDVI", "GNDVI", + "GRNDVI", "ATSAVI", "CIgreen", "CIrededge", "CTVI", "GDVI", + "GEMI", "GOSAVI", "GSAVI", "IVI", "IPVI", "RVI", "MRVI", + "MSAVI", "NormG", "NormNIR", "NormR", "NGRDI", "RI", "DVI", + "TVI", "NDRE"] + + #list of index just with RGB channels + #RGBIndex = ["GLI", "CI", "Hue", "I", "NGRDI", "RI", "S", "IF"] """ def __init__(self, red=None, green=None, blue=None, redEdge=None, nir=None): @@ -189,9 +189,9 @@ def ARVI2(self): def CCCI(self): """ - Canopy Chlorophyll Content Index - https://www.indexdatabase.de/db/i-single.php?id=224 - :return: index + Canopy Chlorophyll Content Index + https://www.indexdatabase.de/db/i-single.php?id=224 + :return: index """ return ((self.nir - self.redEdge) / (self.nir + self.redEdge)) / ( (self.nir - self.red) / (self.nir + self.red) @@ -199,17 +199,17 @@ def CCCI(self): def CVI(self): """ - Chlorophyll vegetation index - https://www.indexdatabase.de/db/i-single.php?id=391 - :return: index + Chlorophyll vegetation index + https://www.indexdatabase.de/db/i-single.php?id=391 + :return: index """ return self.nir * (self.red / (self.green ** 2)) def GLI(self): """ - self.green leaf index - https://www.indexdatabase.de/db/i-single.php?id=375 - :return: index + self.green leaf index + https://www.indexdatabase.de/db/i-single.php?id=375 + :return: index """ return (2 * self.green - self.red - self.blue) / ( 2 * self.green + self.red + self.blue @@ -217,43 +217,43 @@ def GLI(self): def NDVI(self): """ - Normalized Difference self.nir/self.red Normalized Difference Vegetation - Index, Calibrated NDVI - CDVI - https://www.indexdatabase.de/db/i-single.php?id=58 - :return: index + Normalized Difference self.nir/self.red Normalized Difference Vegetation + Index, Calibrated NDVI - CDVI + https://www.indexdatabase.de/db/i-single.php?id=58 + :return: index """ return (self.nir - self.red) / (self.nir + self.red) def BNDVI(self): """ - Normalized Difference self.nir/self.blue self.blue-normalized difference - vegetation index - https://www.indexdatabase.de/db/i-single.php?id=135 - :return: index + Normalized Difference self.nir/self.blue self.blue-normalized difference + vegetation index + https://www.indexdatabase.de/db/i-single.php?id=135 + :return: index """ return (self.nir - self.blue) / (self.nir + self.blue) def redEdgeNDVI(self): """ - Normalized Difference self.rededge/self.red - https://www.indexdatabase.de/db/i-single.php?id=235 - :return: index + Normalized Difference self.rededge/self.red + https://www.indexdatabase.de/db/i-single.php?id=235 + :return: index """ return (self.redEdge - self.red) / (self.redEdge + self.red) def GNDVI(self): """ - Normalized Difference self.nir/self.green self.green NDVI - https://www.indexdatabase.de/db/i-single.php?id=401 - :return: index + Normalized Difference self.nir/self.green self.green NDVI + https://www.indexdatabase.de/db/i-single.php?id=401 + :return: index """ return (self.nir - self.green) / (self.nir + self.green) def GBNDVI(self): """ - self.green-self.blue NDVI - https://www.indexdatabase.de/db/i-single.php?id=186 - :return: index + self.green-self.blue NDVI + https://www.indexdatabase.de/db/i-single.php?id=186 + :return: index """ return (self.nir - (self.green + self.blue)) / ( self.nir + (self.green + self.blue) @@ -261,9 +261,9 @@ def GBNDVI(self): def GRNDVI(self): """ - self.green-self.red NDVI - https://www.indexdatabase.de/db/i-single.php?id=185 - :return: index + self.green-self.red NDVI + https://www.indexdatabase.de/db/i-single.php?id=185 + :return: index """ return (self.nir - (self.green + self.red)) / ( self.nir + (self.green + self.red) @@ -271,17 +271,17 @@ def GRNDVI(self): def RBNDVI(self): """ - self.red-self.blue NDVI - https://www.indexdatabase.de/db/i-single.php?id=187 - :return: index + self.red-self.blue NDVI + https://www.indexdatabase.de/db/i-single.php?id=187 + :return: index """ return (self.nir - (self.blue + self.red)) / (self.nir + (self.blue + self.red)) def PNDVI(self): """ - Pan NDVI - https://www.indexdatabase.de/db/i-single.php?id=188 - :return: index + Pan NDVI + https://www.indexdatabase.de/db/i-single.php?id=188 + :return: index """ return (self.nir - (self.green + self.red + self.blue)) / ( self.nir + (self.green + self.red + self.blue) @@ -289,9 +289,9 @@ def PNDVI(self): def ATSAVI(self, X=0.08, a=1.22, b=0.03): """ - Adjusted transformed soil-adjusted VI - https://www.indexdatabase.de/db/i-single.php?id=209 - :return: index + Adjusted transformed soil-adjusted VI + https://www.indexdatabase.de/db/i-single.php?id=209 + :return: index """ return a * ( (self.nir - a * self.red - b) @@ -300,58 +300,58 @@ def ATSAVI(self, X=0.08, a=1.22, b=0.03): def BWDRVI(self): """ - self.blue-wide dynamic range vegetation index - https://www.indexdatabase.de/db/i-single.php?id=136 - :return: index + self.blue-wide dynamic range vegetation index + https://www.indexdatabase.de/db/i-single.php?id=136 + :return: index """ return (0.1 * self.nir - self.blue) / (0.1 * self.nir + self.blue) def CIgreen(self): """ - Chlorophyll Index self.green - https://www.indexdatabase.de/db/i-single.php?id=128 - :return: index + Chlorophyll Index self.green + https://www.indexdatabase.de/db/i-single.php?id=128 + :return: index """ return (self.nir / self.green) - 1 def CIrededge(self): """ - Chlorophyll Index self.redEdge - https://www.indexdatabase.de/db/i-single.php?id=131 - :return: index + Chlorophyll Index self.redEdge + https://www.indexdatabase.de/db/i-single.php?id=131 + :return: index """ return (self.nir / self.redEdge) - 1 def CI(self): """ - Coloration Index - https://www.indexdatabase.de/db/i-single.php?id=11 - :return: index + Coloration Index + https://www.indexdatabase.de/db/i-single.php?id=11 + :return: index """ return (self.red - self.blue) / self.red def CTVI(self): """ - Corrected Transformed Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=244 - :return: index + Corrected Transformed Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=244 + :return: index """ ndvi = self.NDVI() return ((ndvi + 0.5) / (abs(ndvi + 0.5))) * (abs(ndvi + 0.5) ** (1 / 2)) def GDVI(self): """ - Difference self.nir/self.green self.green Difference Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=27 - :return: index + Difference self.nir/self.green self.green Difference Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=27 + :return: index """ return self.nir - self.green def EVI(self): """ - Enhanced Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=16 - :return: index + Enhanced Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=16 + :return: index """ return 2.5 * ( (self.nir - self.red) / (self.nir + 6 * self.red - 7.5 * self.blue + 1) @@ -359,9 +359,9 @@ def EVI(self): def GEMI(self): """ - Global Environment Monitoring Index - https://www.indexdatabase.de/db/i-single.php?id=25 - :return: index + Global Environment Monitoring Index + https://www.indexdatabase.de/db/i-single.php?id=25 + :return: index """ n = (2 * (self.nir ** 2 - self.red ** 2) + 1.5 * self.nir + 0.5 * self.red) / ( self.nir + self.red + 0.5 @@ -370,27 +370,27 @@ def GEMI(self): def GOSAVI(self, Y=0.16): """ - self.green Optimized Soil Adjusted Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=29 - mit Y = 0,16 - :return: index + self.green Optimized Soil Adjusted Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=29 + mit Y = 0,16 + :return: index """ return (self.nir - self.green) / (self.nir + self.green + Y) def GSAVI(self, L=0.5): """ - self.green Soil Adjusted Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=31 - mit L = 0,5 - :return: index + self.green Soil Adjusted Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=31 + mit L = 0,5 + :return: index """ return ((self.nir - self.green) / (self.nir + self.green + L)) * (1 + L) def Hue(self): """ - Hue - https://www.indexdatabase.de/db/i-single.php?id=34 - :return: index + Hue + https://www.indexdatabase.de/db/i-single.php?id=34 + :return: index """ return np.arctan( ((2 * self.red - self.green - self.blue) / 30.5) * (self.green - self.blue) @@ -398,51 +398,51 @@ def Hue(self): def IVI(self, a=None, b=None): """ - Ideal vegetation index - https://www.indexdatabase.de/db/i-single.php?id=276 - b=intercept of vegetation line - a=soil line slope - :return: index + Ideal vegetation index + https://www.indexdatabase.de/db/i-single.php?id=276 + b=intercept of vegetation line + a=soil line slope + :return: index """ return (self.nir - b) / (a * self.red) def IPVI(self): """ - Infraself.red percentage vegetation index - https://www.indexdatabase.de/db/i-single.php?id=35 - :return: index + Infraself.red percentage vegetation index + https://www.indexdatabase.de/db/i-single.php?id=35 + :return: index """ return (self.nir / ((self.nir + self.red) / 2)) * (self.NDVI() + 1) def I(self): # noqa: E741,E743 """ - Intensity - https://www.indexdatabase.de/db/i-single.php?id=36 - :return: index + Intensity + https://www.indexdatabase.de/db/i-single.php?id=36 + :return: index """ return (self.red + self.green + self.blue) / 30.5 def RVI(self): """ - Ratio-Vegetation-Index - http://www.seos-project.eu/modules/remotesensing/remotesensing-c03-s01-p01.html - :return: index + Ratio-Vegetation-Index + http://www.seos-project.eu/modules/remotesensing/remotesensing-c03-s01-p01.html + :return: index """ return self.nir / self.red def MRVI(self): """ - Modified Normalized Difference Vegetation Index RVI - https://www.indexdatabase.de/db/i-single.php?id=275 - :return: index + Modified Normalized Difference Vegetation Index RVI + https://www.indexdatabase.de/db/i-single.php?id=275 + :return: index """ return (self.RVI() - 1) / (self.RVI() + 1) def MSAVI(self): """ - Modified Soil Adjusted Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=44 - :return: index + Modified Soil Adjusted Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=44 + :return: index """ return ( (2 * self.nir + 1) @@ -451,51 +451,51 @@ def MSAVI(self): def NormG(self): """ - Norm G - https://www.indexdatabase.de/db/i-single.php?id=50 - :return: index + Norm G + https://www.indexdatabase.de/db/i-single.php?id=50 + :return: index """ return self.green / (self.nir + self.red + self.green) def NormNIR(self): """ - Norm self.nir - https://www.indexdatabase.de/db/i-single.php?id=51 - :return: index + Norm self.nir + https://www.indexdatabase.de/db/i-single.php?id=51 + :return: index """ return self.nir / (self.nir + self.red + self.green) def NormR(self): """ - Norm R - https://www.indexdatabase.de/db/i-single.php?id=52 - :return: index + Norm R + https://www.indexdatabase.de/db/i-single.php?id=52 + :return: index """ return self.red / (self.nir + self.red + self.green) def NGRDI(self): """ - Normalized Difference self.green/self.red Normalized self.green self.red - difference index, Visible Atmospherically Resistant Indices self.green - (VIself.green) - https://www.indexdatabase.de/db/i-single.php?id=390 - :return: index + Normalized Difference self.green/self.red Normalized self.green self.red + difference index, Visible Atmospherically Resistant Indices self.green + (VIself.green) + https://www.indexdatabase.de/db/i-single.php?id=390 + :return: index """ return (self.green - self.red) / (self.green + self.red) def RI(self): """ - Normalized Difference self.red/self.green self.redness Index - https://www.indexdatabase.de/db/i-single.php?id=74 - :return: index + Normalized Difference self.red/self.green self.redness Index + https://www.indexdatabase.de/db/i-single.php?id=74 + :return: index """ return (self.red - self.green) / (self.red + self.green) def S(self): """ - Saturation - https://www.indexdatabase.de/db/i-single.php?id=77 - :return: index + Saturation + https://www.indexdatabase.de/db/i-single.php?id=77 + :return: index """ max = np.max([np.max(self.red), np.max(self.green), np.max(self.blue)]) min = np.min([np.min(self.red), np.min(self.green), np.min(self.blue)]) @@ -503,26 +503,26 @@ def S(self): def IF(self): """ - Shape Index - https://www.indexdatabase.de/db/i-single.php?id=79 - :return: index + Shape Index + https://www.indexdatabase.de/db/i-single.php?id=79 + :return: index """ return (2 * self.red - self.green - self.blue) / (self.green - self.blue) def DVI(self): """ - Simple Ratio self.nir/self.red Difference Vegetation Index, Vegetation Index - Number (VIN) - https://www.indexdatabase.de/db/i-single.php?id=12 - :return: index + Simple Ratio self.nir/self.red Difference Vegetation Index, Vegetation Index + Number (VIN) + https://www.indexdatabase.de/db/i-single.php?id=12 + :return: index """ return self.nir / self.red def TVI(self): """ - Transformed Vegetation Index - https://www.indexdatabase.de/db/i-single.php?id=98 - :return: index + Transformed Vegetation Index + https://www.indexdatabase.de/db/i-single.php?id=98 + :return: index """ return (self.NDVI() + 0.5) ** (1 / 2) diff --git a/divide_and_conquer/closest_pair_of_points.py b/divide_and_conquer/closest_pair_of_points.py index eecf53a7450e..cb7fa00d1c8f 100644 --- a/divide_and_conquer/closest_pair_of_points.py +++ b/divide_and_conquer/closest_pair_of_points.py @@ -82,7 +82,7 @@ def dis_between_closest_in_strip(points, points_counts, min_dis=float("inf")): def closest_pair_of_points_sqr(points_sorted_on_x, points_sorted_on_y, points_counts): - """ divide and conquer approach + """divide and conquer approach Parameters : points, points_count (list(tuple(int, int)), int) diff --git a/divide_and_conquer/max_subarray_sum.py b/divide_and_conquer/max_subarray_sum.py index 03bf9d25cb8a..43f58086e078 100644 --- a/divide_and_conquer/max_subarray_sum.py +++ b/divide_and_conquer/max_subarray_sum.py @@ -11,7 +11,7 @@ def max_sum_from_start(array): - """ This function finds the maximum contiguous sum of array from 0 index + """This function finds the maximum contiguous sum of array from 0 index Parameters : array (list[int]) : given array @@ -30,7 +30,7 @@ def max_sum_from_start(array): def max_cross_array_sum(array, left, mid, right): - """ This function finds the maximum contiguous sum of left and right arrays + """This function finds the maximum contiguous sum of left and right arrays Parameters : array, left, mid, right (list[int], int, int, int) @@ -46,7 +46,7 @@ def max_cross_array_sum(array, left, mid, right): def max_subarray_sum(array, left, right): - """ Maximum contiguous sub-array sum, using divide and conquer method + """Maximum contiguous sub-array sum, using divide and conquer method Parameters : array, left, right (list[int], int, int) : diff --git a/divide_and_conquer/strassen_matrix_multiplication.py b/divide_and_conquer/strassen_matrix_multiplication.py index ea54b0f52d29..486258e8bae0 100644 --- a/divide_and_conquer/strassen_matrix_multiplication.py +++ b/divide_and_conquer/strassen_matrix_multiplication.py @@ -29,7 +29,9 @@ def matrix_subtraction(matrix_a: List, matrix_b: List): ] -def split_matrix(a: List,) -> Tuple[List, List, List, List]: +def split_matrix( + a: List, +) -> Tuple[List, List, List, List]: """ Given an even length matrix, returns the top_left, top_right, bot_left, bot_right quadrant. diff --git a/dynamic_programming/rod_cutting.py b/dynamic_programming/rod_cutting.py index a4919742e739..442a39cb1616 100644 --- a/dynamic_programming/rod_cutting.py +++ b/dynamic_programming/rod_cutting.py @@ -13,30 +13,30 @@ def naive_cut_rod_recursive(n: int, prices: list): """ - Solves the rod-cutting problem via naively without using the benefit of dynamic - programming. The results is the same sub-problems are solved several times - leading to an exponential runtime - - Runtime: O(2^n) - - Arguments - ------- - n: int, the length of the rod - prices: list, the prices for each piece of rod. ``p[i-i]`` is the - price for a rod of length ``i`` - - Returns - ------- - The maximum revenue obtainable for a rod of length n given the list of prices - for each piece. - - Examples - -------- - >>> naive_cut_rod_recursive(4, [1, 5, 8, 9]) - 10 - >>> naive_cut_rod_recursive(10, [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]) - 30 - """ + Solves the rod-cutting problem via naively without using the benefit of dynamic + programming. The results is the same sub-problems are solved several times + leading to an exponential runtime + + Runtime: O(2^n) + + Arguments + ------- + n: int, the length of the rod + prices: list, the prices for each piece of rod. ``p[i-i]`` is the + price for a rod of length ``i`` + + Returns + ------- + The maximum revenue obtainable for a rod of length n given the list of prices + for each piece. + + Examples + -------- + >>> naive_cut_rod_recursive(4, [1, 5, 8, 9]) + 10 + >>> naive_cut_rod_recursive(10, [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]) + 30 + """ _enforce_args(n, prices) if n == 0: @@ -52,35 +52,35 @@ def naive_cut_rod_recursive(n: int, prices: list): def top_down_cut_rod(n: int, prices: list): """ - Constructs a top-down dynamic programming solution for the rod-cutting - problem via memoization. This function serves as a wrapper for - _top_down_cut_rod_recursive - - Runtime: O(n^2) - - Arguments - -------- - n: int, the length of the rod - prices: list, the prices for each piece of rod. ``p[i-i]`` is the - price for a rod of length ``i`` - - Note - ---- - For convenience and because Python's lists using 0-indexing, length(max_rev) = - n + 1, to accommodate for the revenue obtainable from a rod of length 0. - - Returns - ------- - The maximum revenue obtainable for a rod of length n given the list of prices - for each piece. - - Examples - ------- - >>> top_down_cut_rod(4, [1, 5, 8, 9]) - 10 - >>> top_down_cut_rod(10, [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]) - 30 - """ + Constructs a top-down dynamic programming solution for the rod-cutting + problem via memoization. This function serves as a wrapper for + _top_down_cut_rod_recursive + + Runtime: O(n^2) + + Arguments + -------- + n: int, the length of the rod + prices: list, the prices for each piece of rod. ``p[i-i]`` is the + price for a rod of length ``i`` + + Note + ---- + For convenience and because Python's lists using 0-indexing, length(max_rev) = + n + 1, to accommodate for the revenue obtainable from a rod of length 0. + + Returns + ------- + The maximum revenue obtainable for a rod of length n given the list of prices + for each piece. + + Examples + ------- + >>> top_down_cut_rod(4, [1, 5, 8, 9]) + 10 + >>> top_down_cut_rod(10, [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]) + 30 + """ _enforce_args(n, prices) max_rev = [float("-inf") for _ in range(n + 1)] return _top_down_cut_rod_recursive(n, prices, max_rev) @@ -88,24 +88,24 @@ def top_down_cut_rod(n: int, prices: list): def _top_down_cut_rod_recursive(n: int, prices: list, max_rev: list): """ - Constructs a top-down dynamic programming solution for the rod-cutting problem - via memoization. - - Runtime: O(n^2) - - Arguments - -------- - n: int, the length of the rod - prices: list, the prices for each piece of rod. ``p[i-i]`` is the - price for a rod of length ``i`` - max_rev: list, the computed maximum revenue for a piece of rod. - ``max_rev[i]`` is the maximum revenue obtainable for a rod of length ``i`` - - Returns - ------- - The maximum revenue obtainable for a rod of length n given the list of prices - for each piece. - """ + Constructs a top-down dynamic programming solution for the rod-cutting problem + via memoization. + + Runtime: O(n^2) + + Arguments + -------- + n: int, the length of the rod + prices: list, the prices for each piece of rod. ``p[i-i]`` is the + price for a rod of length ``i`` + max_rev: list, the computed maximum revenue for a piece of rod. + ``max_rev[i]`` is the maximum revenue obtainable for a rod of length ``i`` + + Returns + ------- + The maximum revenue obtainable for a rod of length n given the list of prices + for each piece. + """ if max_rev[n] >= 0: return max_rev[n] elif n == 0: @@ -125,28 +125,28 @@ def _top_down_cut_rod_recursive(n: int, prices: list, max_rev: list): def bottom_up_cut_rod(n: int, prices: list): """ - Constructs a bottom-up dynamic programming solution for the rod-cutting problem - - Runtime: O(n^2) - - Arguments - ---------- - n: int, the maximum length of the rod. - prices: list, the prices for each piece of rod. ``p[i-i]`` is the - price for a rod of length ``i`` - - Returns - ------- - The maximum revenue obtainable from cutting a rod of length n given - the prices for each piece of rod p. - - Examples - ------- - >>> bottom_up_cut_rod(4, [1, 5, 8, 9]) - 10 - >>> bottom_up_cut_rod(10, [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]) - 30 - """ + Constructs a bottom-up dynamic programming solution for the rod-cutting problem + + Runtime: O(n^2) + + Arguments + ---------- + n: int, the maximum length of the rod. + prices: list, the prices for each piece of rod. ``p[i-i]`` is the + price for a rod of length ``i`` + + Returns + ------- + The maximum revenue obtainable from cutting a rod of length n given + the prices for each piece of rod p. + + Examples + ------- + >>> bottom_up_cut_rod(4, [1, 5, 8, 9]) + 10 + >>> bottom_up_cut_rod(10, [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]) + 30 + """ _enforce_args(n, prices) # length(max_rev) = n + 1, to accommodate for the revenue obtainable from a rod of @@ -166,16 +166,16 @@ def bottom_up_cut_rod(n: int, prices: list): def _enforce_args(n: int, prices: list): """ - Basic checks on the arguments to the rod-cutting algorithms + Basic checks on the arguments to the rod-cutting algorithms - n: int, the length of the rod - prices: list, the price list for each piece of rod. + n: int, the length of the rod + prices: list, the price list for each piece of rod. - Throws ValueError: + Throws ValueError: - if n is negative or there are fewer items in the price list than the length of - the rod - """ + if n is negative or there are fewer items in the price list than the length of + the rod + """ if n < 0: raise ValueError(f"n must be greater than or equal to 0. Got n = {n}") diff --git a/graphs/bfs_shortest_path.py b/graphs/bfs_shortest_path.py index c3664796e677..1655ca64208d 100644 --- a/graphs/bfs_shortest_path.py +++ b/graphs/bfs_shortest_path.py @@ -20,18 +20,18 @@ def bfs_shortest_path(graph: dict, start, goal) -> str: """Find shortest path between `start` and `goal` nodes. - Args: - graph (dict): node/list of neighboring nodes key/value pairs. - start: start node. - goal: target node. - - Returns: - Shortest path between `start` and `goal` nodes as a string of nodes. - 'Not found' string if no path found. - - Example: - >>> bfs_shortest_path(graph, "G", "D") - ['G', 'C', 'A', 'B', 'D'] + Args: + graph (dict): node/list of neighboring nodes key/value pairs. + start: start node. + goal: target node. + + Returns: + Shortest path between `start` and `goal` nodes as a string of nodes. + 'Not found' string if no path found. + + Example: + >>> bfs_shortest_path(graph, "G", "D") + ['G', 'C', 'A', 'B', 'D'] """ # keep track of explored nodes explored = [] @@ -70,22 +70,22 @@ def bfs_shortest_path(graph: dict, start, goal) -> str: def bfs_shortest_path_distance(graph: dict, start, target) -> int: """Find shortest path distance between `start` and `target` nodes. - Args: - graph: node/list of neighboring nodes key/value pairs. - start: node to start search from. - target: node to search for. - - Returns: - Number of edges in shortest path between `start` and `target` nodes. - -1 if no path exists. - - Example: - >>> bfs_shortest_path_distance(graph, "G", "D") - 4 - >>> bfs_shortest_path_distance(graph, "A", "A") - 0 - >>> bfs_shortest_path_distance(graph, "A", "H") - -1 + Args: + graph: node/list of neighboring nodes key/value pairs. + start: node to start search from. + target: node to search for. + + Returns: + Number of edges in shortest path between `start` and `target` nodes. + -1 if no path exists. + + Example: + >>> bfs_shortest_path_distance(graph, "G", "D") + 4 + >>> bfs_shortest_path_distance(graph, "A", "A") + 0 + >>> bfs_shortest_path_distance(graph, "A", "H") + -1 """ if not graph or start not in graph or target not in graph: return -1 diff --git a/graphs/depth_first_search.py b/graphs/depth_first_search.py index 1e2231907b78..9ec7083c7fc1 100644 --- a/graphs/depth_first_search.py +++ b/graphs/depth_first_search.py @@ -17,18 +17,18 @@ def depth_first_search(graph: Dict, start: str) -> Set[int]: """Depth First Search on Graph - :param graph: directed graph in dictionary format - :param vertex: starting vectex as a string - :returns: the trace of the search - >>> G = { "A": ["B", "C", "D"], "B": ["A", "D", "E"], - ... "C": ["A", "F"], "D": ["B", "D"], "E": ["B", "F"], - ... "F": ["C", "E", "G"], "G": ["F"] } - >>> start = "A" - >>> output_G = list({'A', 'B', 'C', 'D', 'E', 'F', 'G'}) - >>> all(x in output_G for x in list(depth_first_search(G, "A"))) - True - >>> all(x in output_G for x in list(depth_first_search(G, "G"))) - True + :param graph: directed graph in dictionary format + :param vertex: starting vectex as a string + :returns: the trace of the search + >>> G = { "A": ["B", "C", "D"], "B": ["A", "D", "E"], + ... "C": ["A", "F"], "D": ["B", "D"], "E": ["B", "F"], + ... "F": ["C", "E", "G"], "G": ["F"] } + >>> start = "A" + >>> output_G = list({'A', 'B', 'C', 'D', 'E', 'F', 'G'}) + >>> all(x in output_G for x in list(depth_first_search(G, "A"))) + True + >>> all(x in output_G for x in list(depth_first_search(G, "G"))) + True """ explored, stack = set(start), [start] while stack: diff --git a/graphs/prim.py b/graphs/prim.py index a1d46a5a12a4..f7376cfb48ca 100644 --- a/graphs/prim.py +++ b/graphs/prim.py @@ -56,14 +56,14 @@ def connect(graph, a, b, edge): def prim(graph: list, root: Vertex) -> list: """Prim's Algorithm. - Runtime: - O(mn) with `m` edges and `n` vertices + Runtime: + O(mn) with `m` edges and `n` vertices - Return: - List with the edges of a Minimum Spanning Tree + Return: + List with the edges of a Minimum Spanning Tree - Usage: - prim(graph, graph[0]) + Usage: + prim(graph, graph[0]) """ a = [] for u in graph: @@ -86,14 +86,14 @@ def prim(graph: list, root: Vertex) -> list: def prim_heap(graph: list, root: Vertex) -> Iterator[tuple]: """Prim's Algorithm with min heap. - Runtime: - O((m + n)log n) with `m` edges and `n` vertices + Runtime: + O((m + n)log n) with `m` edges and `n` vertices - Yield: - Edges of a Minimum Spanning Tree + Yield: + Edges of a Minimum Spanning Tree - Usage: - prim(graph, graph[0]) + Usage: + prim(graph, graph[0]) """ for u in graph: u.key = math.inf diff --git a/hashes/md5.py b/hashes/md5.py index 85565533d175..b7888fb610ac 100644 --- a/hashes/md5.py +++ b/hashes/md5.py @@ -94,9 +94,7 @@ def not32(i): def sum32(a, b): - """ - - """ + """""" return (a + b) % 2 ** 32 diff --git a/linear_algebra/src/lib.py b/linear_algebra/src/lib.py index 10b9da65863f..353c8334093b 100644 --- a/linear_algebra/src/lib.py +++ b/linear_algebra/src/lib.py @@ -26,29 +26,29 @@ class Vector: """ - This class represents a vector of arbitrary size. - You need to give the vector components. - - Overview about the methods: - - constructor(components : list) : init the vector - set(components : list) : changes the vector components. - __str__() : toString method - component(i : int): gets the i-th component (start by 0) - __len__() : gets the size of the vector (number of components) - euclidLength() : returns the euclidean length of the vector. - operator + : vector addition - operator - : vector subtraction - operator * : scalar multiplication and dot product - copy() : copies this vector and returns it. - changeComponent(pos,value) : changes the specified component. - TODO: compare-operator + This class represents a vector of arbitrary size. + You need to give the vector components. + + Overview about the methods: + + constructor(components : list) : init the vector + set(components : list) : changes the vector components. + __str__() : toString method + component(i : int): gets the i-th component (start by 0) + __len__() : gets the size of the vector (number of components) + euclidLength() : returns the euclidean length of the vector. + operator + : vector addition + operator - : vector subtraction + operator * : scalar multiplication and dot product + copy() : copies this vector and returns it. + changeComponent(pos,value) : changes the specified component. + TODO: compare-operator """ def __init__(self, components=None): """ - input: components or nothing - simple constructor for init the vector + input: components or nothing + simple constructor for init the vector """ if components is None: components = [] @@ -56,9 +56,9 @@ def __init__(self, components=None): def set(self, components): """ - input: new components - changes the components of the vector. - replace the components with newer one. + input: new components + changes the components of the vector. + replace the components with newer one. """ if len(components) > 0: self.__components = list(components) @@ -67,14 +67,14 @@ def set(self, components): def __str__(self): """ - returns a string representation of the vector + returns a string representation of the vector """ return "(" + ",".join(map(str, self.__components)) + ")" def component(self, i): """ - input: index (start at 0) - output: the i-th component of the vector. + input: index (start at 0) + output: the i-th component of the vector. """ if type(i) is int and -len(self.__components) <= i < len(self.__components): return self.__components[i] @@ -83,13 +83,13 @@ def component(self, i): def __len__(self): """ - returns the size of the vector + returns the size of the vector """ return len(self.__components) def euclidLength(self): """ - returns the euclidean length of the vector + returns the euclidean length of the vector """ summe = 0 for c in self.__components: @@ -98,9 +98,9 @@ def euclidLength(self): def __add__(self, other): """ - input: other vector - assumes: other vector has the same size - returns a new vector that represents the sum. + input: other vector + assumes: other vector has the same size + returns a new vector that represents the sum. """ size = len(self) if size == len(other): @@ -111,9 +111,9 @@ def __add__(self, other): def __sub__(self, other): """ - input: other vector - assumes: other vector has the same size - returns a new vector that represents the difference. + input: other vector + assumes: other vector has the same size + returns a new vector that represents the difference. """ size = len(self) if size == len(other): @@ -124,8 +124,8 @@ def __sub__(self, other): def __mul__(self, other): """ - mul implements the scalar multiplication - and the dot-product + mul implements the scalar multiplication + and the dot-product """ if isinstance(other, float) or isinstance(other, int): ans = [c * other for c in self.__components] @@ -141,15 +141,15 @@ def __mul__(self, other): def copy(self): """ - copies this vector and returns it. + copies this vector and returns it. """ return Vector(self.__components) def changeComponent(self, pos, value): """ - input: an index (pos) and a value - changes the specified component (pos) with the - 'value' + input: an index (pos) and a value + changes the specified component (pos) with the + 'value' """ # precondition assert -len(self.__components) <= pos < len(self.__components) @@ -158,7 +158,7 @@ def changeComponent(self, pos, value): def zeroVector(dimension): """ - returns a zero-vector of size 'dimension' + returns a zero-vector of size 'dimension' """ # precondition assert isinstance(dimension, int) @@ -167,8 +167,8 @@ def zeroVector(dimension): def unitBasisVector(dimension, pos): """ - returns a unit basis vector with a One - at index 'pos' (indexing at 0) + returns a unit basis vector with a One + at index 'pos' (indexing at 0) """ # precondition assert isinstance(dimension, int) and (isinstance(pos, int)) @@ -179,9 +179,9 @@ def unitBasisVector(dimension, pos): def axpy(scalar, x, y): """ - input: a 'scalar' and two vectors 'x' and 'y' - output: a vector - computes the axpy operation + input: a 'scalar' and two vectors 'x' and 'y' + output: a vector + computes the axpy operation """ # precondition assert ( @@ -194,10 +194,10 @@ def axpy(scalar, x, y): def randomVector(N, a, b): """ - input: size (N) of the vector. - random range (a,b) - output: returns a random vector of size N, with - random integer components between 'a' and 'b'. + input: size (N) of the vector. + random range (a,b) + output: returns a random vector of size N, with + random integer components between 'a' and 'b'. """ random.seed(None) ans = [random.randint(a, b) for i in range(N)] @@ -224,8 +224,8 @@ class Matrix: def __init__(self, matrix, w, h): """ - simple constructor for initializing - the matrix with components. + simple constructor for initializing + the matrix with components. """ self.__matrix = matrix self.__width = w @@ -233,8 +233,8 @@ def __init__(self, matrix, w, h): def __str__(self): """ - returns a string representation of this - matrix. + returns a string representation of this + matrix. """ ans = "" for i in range(self.__height): @@ -248,7 +248,7 @@ def __str__(self): def changeComponent(self, x, y, value): """ - changes the x-y component of this matrix + changes the x-y component of this matrix """ if 0 <= x < self.__height and 0 <= y < self.__width: self.__matrix[x][y] = value @@ -257,7 +257,7 @@ def changeComponent(self, x, y, value): def component(self, x, y): """ - returns the specified (x,y) component + returns the specified (x,y) component """ if 0 <= x < self.__height and 0 <= y < self.__width: return self.__matrix[x][y] @@ -266,19 +266,19 @@ def component(self, x, y): def width(self): """ - getter for the width + getter for the width """ return self.__width def height(self): """ - getter for the height + getter for the height """ return self.__height def determinate(self) -> float: """ - returns the determinate of an nxn matrix using Laplace expansion + returns the determinate of an nxn matrix using Laplace expansion """ if self.__height == self.__width and self.__width >= 2: total = 0 @@ -305,8 +305,8 @@ def determinate(self) -> float: def __mul__(self, other): """ - implements the matrix-vector multiplication. - implements the matrix-scalar multiplication + implements the matrix-vector multiplication. + implements the matrix-scalar multiplication """ if isinstance(other, Vector): # vector-matrix if len(other) == self.__width: @@ -332,7 +332,7 @@ def __mul__(self, other): def __add__(self, other): """ - implements the matrix-addition. + implements the matrix-addition. """ if self.__width == other.width() and self.__height == other.height(): matrix = [] @@ -347,7 +347,7 @@ def __add__(self, other): def __sub__(self, other): """ - implements the matrix-subtraction. + implements the matrix-subtraction. """ if self.__width == other.width() and self.__height == other.height(): matrix = [] @@ -363,7 +363,7 @@ def __sub__(self, other): def squareZeroMatrix(N): """ - returns a square zero-matrix of dimension NxN + returns a square zero-matrix of dimension NxN """ ans = [[0] * N for i in range(N)] return Matrix(ans, N, N) @@ -371,8 +371,8 @@ def squareZeroMatrix(N): def randomMatrix(W, H, a, b): """ - returns a random matrix WxH with integer components - between 'a' and 'b' + returns a random matrix WxH with integer components + between 'a' and 'b' """ random.seed(None) matrix = [[random.randint(a, b) for j in range(W)] for i in range(H)] diff --git a/linear_algebra/src/test_linear_algebra.py b/linear_algebra/src/test_linear_algebra.py index 8db480ceb29d..668ffe858b99 100644 --- a/linear_algebra/src/test_linear_algebra.py +++ b/linear_algebra/src/test_linear_algebra.py @@ -14,7 +14,7 @@ class Test(unittest.TestCase): def test_component(self): """ - test for method component + test for method component """ x = Vector([1, 2, 3]) self.assertEqual(x.component(0), 1) @@ -23,28 +23,28 @@ def test_component(self): def test_str(self): """ - test for toString() method + test for toString() method """ x = Vector([0, 0, 0, 0, 0, 1]) self.assertEqual(str(x), "(0,0,0,0,0,1)") def test_size(self): """ - test for size()-method + test for size()-method """ x = Vector([1, 2, 3, 4]) self.assertEqual(len(x), 4) def test_euclidLength(self): """ - test for the eulidean length + test for the eulidean length """ x = Vector([1, 2]) self.assertAlmostEqual(x.euclidLength(), 2.236, 3) def test_add(self): """ - test for + operator + test for + operator """ x = Vector([1, 2, 3]) y = Vector([1, 1, 1]) @@ -54,7 +54,7 @@ def test_add(self): def test_sub(self): """ - test for - operator + test for - operator """ x = Vector([1, 2, 3]) y = Vector([1, 1, 1]) @@ -64,7 +64,7 @@ def test_sub(self): def test_mul(self): """ - test for * operator + test for * operator """ x = Vector([1, 2, 3]) a = Vector([2, -1, 4]) # for test of dot-product @@ -74,19 +74,19 @@ def test_mul(self): def test_zeroVector(self): """ - test for the global function zeroVector(...) + test for the global function zeroVector(...) """ self.assertTrue(str(zeroVector(10)).count("0") == 10) def test_unitBasisVector(self): """ - test for the global function unitBasisVector(...) + test for the global function unitBasisVector(...) """ self.assertEqual(str(unitBasisVector(3, 1)), "(0,1,0)") def test_axpy(self): """ - test for the global function axpy(...) (operation) + test for the global function axpy(...) (operation) """ x = Vector([1, 2, 3]) y = Vector([1, 0, 1]) @@ -94,7 +94,7 @@ def test_axpy(self): def test_copy(self): """ - test for the copy()-method + test for the copy()-method """ x = Vector([1, 0, 0, 0, 0, 0]) y = x.copy() @@ -102,7 +102,7 @@ def test_copy(self): def test_changeComponent(self): """ - test for the changeComponent(...)-method + test for the changeComponent(...)-method """ x = Vector([1, 0, 0]) x.changeComponent(0, 0) @@ -115,7 +115,7 @@ def test_str_matrix(self): def test_determinate(self): """ - test for determinate() + test for determinate() """ A = Matrix([[1, 1, 4, 5], [3, 3, 3, 2], [5, 1, 9, 0], [9, 7, 7, 9]], 4, 4) self.assertEqual(-376, A.determinate()) diff --git a/machine_learning/decision_tree.py b/machine_learning/decision_tree.py index fe1d54736563..ace6fb0fa883 100644 --- a/machine_learning/decision_tree.py +++ b/machine_learning/decision_tree.py @@ -135,8 +135,7 @@ def predict(self, x): class Test_Decision_Tree: - """Decision Tres test class - """ + """Decision Tres test class""" @staticmethod def helper_mean_squared_error_test(labels, prediction): diff --git a/machine_learning/k_means_clust.py b/machine_learning/k_means_clust.py index 4da904ae3568..130e7f1ad669 100644 --- a/machine_learning/k_means_clust.py +++ b/machine_learning/k_means_clust.py @@ -132,12 +132,12 @@ def kmeans( data, k, initial_centroids, maxiter=500, record_heterogeneity=None, verbose=False ): """This function runs k-means on given data and initial set of centroids. - maxiter: maximum number of iterations to run.(default=500) - record_heterogeneity: (optional) a list, to store the history of heterogeneity - as function of iterations - if None, do not store the history. - verbose: if True, print how many data points changed their cluster labels in - each iteration""" + maxiter: maximum number of iterations to run.(default=500) + record_heterogeneity: (optional) a list, to store the history of heterogeneity + as function of iterations + if None, do not store the history. + verbose: if True, print how many data points changed their cluster labels in + each iteration""" centroids = initial_centroids[:] prev_cluster_assignment = None diff --git a/machine_learning/linear_discriminant_analysis.py b/machine_learning/linear_discriminant_analysis.py index b26da2628982..22ee63a5a62b 100644 --- a/machine_learning/linear_discriminant_analysis.py +++ b/machine_learning/linear_discriminant_analysis.py @@ -153,7 +153,7 @@ def calculate_variance(items: list, means: list, total_count: int) -> float: def predict_y_values( x_items: list, means: list, variance: float, probabilities: list ) -> list: - """ This function predicts new indexes(groups for our data) + """This function predicts new indexes(groups for our data) :param x_items: a list containing all items(gaussian distribution of all classes) :param means: a list containing real mean values of each class :param variance: calculated value of variance by calculate_variance function diff --git a/machine_learning/linear_regression.py b/machine_learning/linear_regression.py index 8c0dfebbca9d..a726629efe00 100644 --- a/machine_learning/linear_regression.py +++ b/machine_learning/linear_regression.py @@ -12,7 +12,7 @@ def collect_dataset(): - """ Collect dataset of CSGO + """Collect dataset of CSGO The dataset contains ADR vs Rating of a Player :return : dataset obtained from the link, as matrix """ @@ -32,7 +32,7 @@ def collect_dataset(): def run_steep_gradient_descent(data_x, data_y, len_data, alpha, theta): - """ Run steep gradient descent and updates the Feature vector accordingly_ + """Run steep gradient descent and updates the Feature vector accordingly_ :param data_x : contains the dataset :param data_y : contains the output associated with each data-entry :param len_data : length of the data_ @@ -51,7 +51,7 @@ def run_steep_gradient_descent(data_x, data_y, len_data, alpha, theta): def sum_of_square_error(data_x, data_y, len_data, theta): - """ Return sum of square error for error calculation + """Return sum of square error for error calculation :param data_x : contains our dataset :param data_y : contains the output (result vector) :param len_data : len of the dataset @@ -66,7 +66,7 @@ def sum_of_square_error(data_x, data_y, len_data, theta): def run_linear_regression(data_x, data_y): - """ Implement Linear regression over the dataset + """Implement Linear regression over the dataset :param data_x : contains our dataset :param data_y : contains the output (result vector) :return : feature for line of best fit (Feature vector) diff --git a/maths/kth_lexicographic_permutation.py b/maths/kth_lexicographic_permutation.py index 491c1c84fa85..23eab626fbf8 100644 --- a/maths/kth_lexicographic_permutation.py +++ b/maths/kth_lexicographic_permutation.py @@ -1,18 +1,18 @@ def kthPermutation(k, n): """ - Finds k'th lexicographic permutation (in increasing order) of - 0,1,2,...n-1 in O(n^2) time. - - Examples: - First permutation is always 0,1,2,...n - >>> kthPermutation(0,5) - [0, 1, 2, 3, 4] - - The order of permutation of 0,1,2,3 is [0,1,2,3], [0,1,3,2], [0,2,1,3], - [0,2,3,1], [0,3,1,2], [0,3,2,1], [1,0,2,3], [1,0,3,2], [1,2,0,3], - [1,2,3,0], [1,3,0,2] - >>> kthPermutation(10,4) - [1, 3, 0, 2] + Finds k'th lexicographic permutation (in increasing order) of + 0,1,2,...n-1 in O(n^2) time. + + Examples: + First permutation is always 0,1,2,...n + >>> kthPermutation(0,5) + [0, 1, 2, 3, 4] + + The order of permutation of 0,1,2,3 is [0,1,2,3], [0,1,3,2], [0,2,1,3], + [0,2,3,1], [0,3,1,2], [0,3,2,1], [1,0,2,3], [1,0,3,2], [1,2,0,3], + [1,2,3,0], [1,3,0,2] + >>> kthPermutation(10,4) + [1, 3, 0, 2] """ # Factorails from 1! to (n-1)! factorials = [1] diff --git a/maths/newton_raphson.py b/maths/newton_raphson.py index d8a98dfa6703..f2b7cb9766d2 100644 --- a/maths/newton_raphson.py +++ b/maths/newton_raphson.py @@ -12,8 +12,8 @@ def calc_derivative(f, a, h=0.001): """ - Calculates derivative at point a for function f using finite difference - method + Calculates derivative at point a for function f using finite difference + method """ return (f(a + h) - f(a - h)) / (2 * h) diff --git a/maths/prime_sieve_eratosthenes.py b/maths/prime_sieve_eratosthenes.py index 0ebdfdb94e15..da3ae472ce23 100644 --- a/maths/prime_sieve_eratosthenes.py +++ b/maths/prime_sieve_eratosthenes.py @@ -19,9 +19,9 @@ def prime_sieve_eratosthenes(num): print the prime numbers up to n >>> prime_sieve_eratosthenes(10) - 2 3 5 7 + 2,3,5,7, >>> prime_sieve_eratosthenes(20) - 2 3 5 7 11 13 17 19 + 2,3,5,7,11,13,17,19, """ primes = [True for i in range(num + 1)] @@ -35,10 +35,13 @@ def prime_sieve_eratosthenes(num): for prime in range(2, num + 1): if primes[prime]: - print(prime, end=" ") + print(prime, end=",") if __name__ == "__main__": + import doctest + + doctest.testmod() num = int(input()) prime_sieve_eratosthenes(num) diff --git a/maths/relu.py b/maths/relu.py index 89667ab3e73f..826ada65fa16 100644 --- a/maths/relu.py +++ b/maths/relu.py @@ -16,20 +16,20 @@ def relu(vector: List[float]): """ - Implements the relu function + Implements the relu function - Parameters: - vector (np.array,list,tuple): A numpy array of shape (1,n) - consisting of real values or a similar list,tuple + Parameters: + vector (np.array,list,tuple): A numpy array of shape (1,n) + consisting of real values or a similar list,tuple - Returns: - relu_vec (np.array): The input numpy array, after applying - relu. + Returns: + relu_vec (np.array): The input numpy array, after applying + relu. - >>> vec = np.array([-1, 0, 5]) - >>> relu(vec) - array([0, 0, 5]) + >>> vec = np.array([-1, 0, 5]) + >>> relu(vec) + array([0, 0, 5]) """ # compare two arrays and then return element-wise maxima. diff --git a/maths/softmax.py b/maths/softmax.py index 92ff4ca27b88..e021a7f8a6fe 100644 --- a/maths/softmax.py +++ b/maths/softmax.py @@ -15,28 +15,28 @@ def softmax(vector): """ - Implements the softmax function + Implements the softmax function - Parameters: - vector (np.array,list,tuple): A numpy array of shape (1,n) - consisting of real values or a similar list,tuple + Parameters: + vector (np.array,list,tuple): A numpy array of shape (1,n) + consisting of real values or a similar list,tuple - Returns: - softmax_vec (np.array): The input numpy array after applying - softmax. + Returns: + softmax_vec (np.array): The input numpy array after applying + softmax. - The softmax vector adds up to one. We need to ceil to mitigate for - precision - >>> np.ceil(np.sum(softmax([1,2,3,4]))) - 1.0 + The softmax vector adds up to one. We need to ceil to mitigate for + precision + >>> np.ceil(np.sum(softmax([1,2,3,4]))) + 1.0 - >>> vec = np.array([5,5]) - >>> softmax(vec) - array([0.5, 0.5]) + >>> vec = np.array([5,5]) + >>> softmax(vec) + array([0.5, 0.5]) - >>> softmax([0]) - array([1.]) + >>> softmax([0]) + array([1.]) """ # Calculate e^x for each x in your vector where e is Euler's diff --git a/maths/sum_of_geometric_progression.py b/maths/sum_of_geometric_progression.py index 614d6646ec43..f29dd8005cff 100644 --- a/maths/sum_of_geometric_progression.py +++ b/maths/sum_of_geometric_progression.py @@ -1,7 +1,7 @@ def sum_of_geometric_progression( first_term: int, common_ratio: int, num_of_terms: int ) -> float: - """" + """ " Return the sum of n terms in a geometric progression. >>> sum_of_geometric_progression(1, 2, 10) 1023.0 diff --git a/maths/zellers_congruence.py b/maths/zellers_congruence.py index 8608b32f3ee3..2d4a22a0a5ba 100644 --- a/maths/zellers_congruence.py +++ b/maths/zellers_congruence.py @@ -63,8 +63,7 @@ def zeller(date_input: str) -> str: >>> zeller('01-31-19082939') Traceback (most recent call last): ... - ValueError: Must be 10 characters long -""" + ValueError: Must be 10 characters long""" # Days of the week for response days = { diff --git a/matrix/matrix_operation.py b/matrix/matrix_operation.py index 42a94da12375..3838dab6be09 100644 --- a/matrix/matrix_operation.py +++ b/matrix/matrix_operation.py @@ -168,7 +168,9 @@ def main(): matrix_c = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44]] matrix_d = [[3, 0, 2], [2, 0, -2], [0, 1, 1]] print(f"Add Operation, {add(matrix_a, matrix_b) = } \n") - print(f"Multiply Operation, {multiply(matrix_a, matrix_b) = } \n",) + print( + f"Multiply Operation, {multiply(matrix_a, matrix_b) = } \n", + ) print(f"Identity: {identity(5)}\n") print(f"Minor of {matrix_c} = {minor(matrix_c, 1, 2)} \n") print(f"Determinant of {matrix_b} = {determinant(matrix_b)} \n") diff --git a/other/activity_selection.py b/other/activity_selection.py index 8876eb2930fc..c03956cce5d2 100644 --- a/other/activity_selection.py +++ b/other/activity_selection.py @@ -16,14 +16,14 @@ def printMaxActivities(start, finish): >>> finish = [2, 4, 6, 7, 9, 9] >>> printMaxActivities(start, finish) The following activities are selected: - 0 1 3 4 + 0,1,3,4, """ n = len(finish) print("The following activities are selected:") # The first activity is always selected i = 0 - print(i, end=" ") + print(i, end=",") # Consider rest of the activities for j in range(n): @@ -32,16 +32,15 @@ def printMaxActivities(start, finish): # or equal to the finish time of previously # selected activity, then select it if start[j] >= finish[i]: - print(j, end=" ") + print(j, end=",") i = j -# Driver program to test above function -start = [1, 3, 0, 5, 8, 5] -finish = [2, 4, 6, 7, 9, 9] -printMaxActivities(start, finish) +if __name__ == "__main__": + import doctest -""" -The following activities are selected: -0 1 3 4 -""" + doctest.testmod() + + start = [1, 3, 0, 5, 8, 5] + finish = [2, 4, 6, 7, 9, 9] + printMaxActivities(start, finish) diff --git a/other/game_of_life.py b/other/game_of_life.py index 651467969fad..09863993dc3a 100644 --- a/other/game_of_life.py +++ b/other/game_of_life.py @@ -52,7 +52,7 @@ def seed(canvas): def run(canvas): - """ This function runs the rules of game through all points, and changes their + """This function runs the rules of game through all points, and changes their status accordingly.(in the same canvas) @Args: -- diff --git a/other/least_recently_used.py b/other/least_recently_used.py index 1b901d544b8d..213339636469 100644 --- a/other/least_recently_used.py +++ b/other/least_recently_used.py @@ -12,7 +12,7 @@ class LRUCache: @abstractmethod def __init__(self, n: int): - """ Creates an empty store and map for the keys. + """Creates an empty store and map for the keys. The LRUCache is set the size n. """ self.dq_store = deque() @@ -26,9 +26,9 @@ def __init__(self, n: int): def refer(self, x): """ - Looks for a page in the cache store and adds reference to the set. - Remove the least recently used key if the store is full. - Update store to reflect recent access. + Looks for a page in the cache store and adds reference to the set. + Remove the least recently used key if the store is full. + Update store to reflect recent access. """ if x not in self.key_reference_map: if len(self.dq_store) == LRUCache._MAX_CAPACITY: @@ -47,7 +47,7 @@ def refer(self, x): def display(self): """ - Prints all the elements in the store. + Prints all the elements in the store. """ for k in self.dq_store: print(k) diff --git a/other/magicdiamondpattern.py b/other/magicdiamondpattern.py index 37b5e4809f47..71bc50b51fc2 100644 --- a/other/magicdiamondpattern.py +++ b/other/magicdiamondpattern.py @@ -6,7 +6,7 @@ def floyd(n): """ Parameters: n : size of pattern - """ + """ for i in range(0, n): for j in range(0, n - i - 1): # printing spaces print(" ", end="") @@ -20,7 +20,7 @@ def reverse_floyd(n): """ Parameters: n : size of pattern - """ + """ for i in range(n, 0, -1): for j in range(i, 0, -1): # printing stars print("* ", end="") @@ -34,7 +34,7 @@ def pretty_print(n): """ Parameters: n : size of pattern - """ + """ if n <= 0: print(" ... .... nothing printing :(") return diff --git a/other/primelib.py b/other/primelib.py index a6d1d7dfb324..37883d9cf591 100644 --- a/other/primelib.py +++ b/other/primelib.py @@ -43,8 +43,8 @@ def isPrime(number): """ - input: positive integer 'number' - returns true if 'number' is prime otherwise false. + input: positive integer 'number' + returns true if 'number' is prime otherwise false. """ # precondition @@ -77,11 +77,11 @@ def isPrime(number): def sieveEr(N): """ - input: positive integer 'N' > 2 - returns a list of prime numbers from 2 up to N. + input: positive integer 'N' > 2 + returns a list of prime numbers from 2 up to N. - This function implements the algorithm called - sieve of erathostenes. + This function implements the algorithm called + sieve of erathostenes. """ @@ -115,9 +115,9 @@ def sieveEr(N): def getPrimeNumbers(N): """ - input: positive integer 'N' > 2 - returns a list of prime numbers from 2 up to N (inclusive) - This function is more efficient as function 'sieveEr(...)' + input: positive integer 'N' > 2 + returns a list of prime numbers from 2 up to N (inclusive) + This function is more efficient as function 'sieveEr(...)' """ # precondition @@ -144,8 +144,8 @@ def getPrimeNumbers(N): def primeFactorization(number): """ - input: positive integer 'number' - returns a list of the prime number factors of 'number' + input: positive integer 'number' + returns a list of the prime number factors of 'number' """ # precondition @@ -188,8 +188,8 @@ def primeFactorization(number): def greatestPrimeFactor(number): """ - input: positive integer 'number' >= 0 - returns the greatest prime number factor of 'number' + input: positive integer 'number' >= 0 + returns the greatest prime number factor of 'number' """ # precondition @@ -215,8 +215,8 @@ def greatestPrimeFactor(number): def smallestPrimeFactor(number): """ - input: integer 'number' >= 0 - returns the smallest prime number factor of 'number' + input: integer 'number' >= 0 + returns the smallest prime number factor of 'number' """ # precondition @@ -242,8 +242,8 @@ def smallestPrimeFactor(number): def isEven(number): """ - input: integer 'number' - returns true if 'number' is even, otherwise false. + input: integer 'number' + returns true if 'number' is even, otherwise false. """ # precondition @@ -258,8 +258,8 @@ def isEven(number): def isOdd(number): """ - input: integer 'number' - returns true if 'number' is odd, otherwise false. + input: integer 'number' + returns true if 'number' is odd, otherwise false. """ # precondition @@ -274,9 +274,9 @@ def isOdd(number): def goldbach(number): """ - Goldbach's assumption - input: a even positive integer 'number' > 2 - returns a list of two prime numbers whose sum is equal to 'number' + Goldbach's assumption + input: a even positive integer 'number' > 2 + returns a list of two prime numbers whose sum is equal to 'number' """ # precondition @@ -329,9 +329,9 @@ def goldbach(number): def gcd(number1, number2): """ - Greatest common divisor - input: two positive integer 'number1' and 'number2' - returns the greatest common divisor of 'number1' and 'number2' + Greatest common divisor + input: two positive integer 'number1' and 'number2' + returns the greatest common divisor of 'number1' and 'number2' """ # precondition @@ -363,9 +363,9 @@ def gcd(number1, number2): def kgV(number1, number2): """ - Least common multiple - input: two positive integer 'number1' and 'number2' - returns the least common multiple of 'number1' and 'number2' + Least common multiple + input: two positive integer 'number1' and 'number2' + returns the least common multiple of 'number1' and 'number2' """ # precondition @@ -443,9 +443,9 @@ def kgV(number1, number2): def getPrime(n): """ - Gets the n-th prime number. - input: positive integer 'n' >= 0 - returns the n-th prime number, beginning at index 0 + Gets the n-th prime number. + input: positive integer 'n' >= 0 + returns the n-th prime number, beginning at index 0 """ # precondition @@ -478,10 +478,10 @@ def getPrime(n): def getPrimesBetween(pNumber1, pNumber2): """ - input: prime numbers 'pNumber1' and 'pNumber2' - pNumber1 < pNumber2 - returns a list of all prime numbers between 'pNumber1' (exclusive) - and 'pNumber2' (exclusive) + input: prime numbers 'pNumber1' and 'pNumber2' + pNumber1 < pNumber2 + returns a list of all prime numbers between 'pNumber1' (exclusive) + and 'pNumber2' (exclusive) """ # precondition @@ -522,8 +522,8 @@ def getPrimesBetween(pNumber1, pNumber2): def getDivisors(n): """ - input: positive integer 'n' >= 1 - returns all divisors of n (inclusive 1 and 'n') + input: positive integer 'n' >= 1 + returns all divisors of n (inclusive 1 and 'n') """ # precondition @@ -547,8 +547,8 @@ def getDivisors(n): def isPerfectNumber(number): """ - input: positive integer 'number' > 1 - returns true if 'number' is a perfect number otherwise false. + input: positive integer 'number' > 1 + returns true if 'number' is a perfect number otherwise false. """ # precondition @@ -574,9 +574,9 @@ def isPerfectNumber(number): def simplifyFraction(numerator, denominator): """ - input: two integer 'numerator' and 'denominator' - assumes: 'denominator' != 0 - returns: a tuple with simplify numerator and denominator. + input: two integer 'numerator' and 'denominator' + assumes: 'denominator' != 0 + returns: a tuple with simplify numerator and denominator. """ # precondition @@ -604,8 +604,8 @@ def simplifyFraction(numerator, denominator): def factorial(n): """ - input: positive integer 'n' - returns the factorial of 'n' (n!) + input: positive integer 'n' + returns the factorial of 'n' (n!) """ # precondition @@ -624,8 +624,8 @@ def factorial(n): def fib(n): """ - input: positive integer 'n' - returns the n-th fibonacci term , indexing by 0 + input: positive integer 'n' + returns the n-th fibonacci term , indexing by 0 """ # precondition diff --git a/project_euler/problem_09/sol2.py b/project_euler/problem_09/sol2.py index de7b12d40c09..d16835ca09a2 100644 --- a/project_euler/problem_09/sol2.py +++ b/project_euler/problem_09/sol2.py @@ -23,8 +23,7 @@ def solution(n): product = -1 d = 0 for a in range(1, n // 3): - """Solving the two equations a**2+b**2=c**2 and a+b+c=N eliminating c - """ + """Solving the two equations a**2+b**2=c**2 and a+b+c=N eliminating c""" b = (n * n - 2 * a * n) // (2 * n - 2 * a) c = n - a - b if c * c == (a * a + b * b): diff --git a/project_euler/problem_10/sol3.py b/project_euler/problem_10/sol3.py index e5bc0731d8ab..739aaa9f16bb 100644 --- a/project_euler/problem_10/sol3.py +++ b/project_euler/problem_10/sol3.py @@ -12,7 +12,7 @@ def prime_sum(n: int) -> int: - """ Returns the sum of all the primes below n. + """Returns the sum of all the primes below n. >>> prime_sum(2_000_000) 142913828922 diff --git a/project_euler/problem_15/sol1.py b/project_euler/problem_15/sol1.py index 1be7d10ed674..feeb3ddab57a 100644 --- a/project_euler/problem_15/sol1.py +++ b/project_euler/problem_15/sol1.py @@ -8,31 +8,31 @@ def lattice_paths(n): """ - Returns the number of paths possible in a n x n grid starting at top left - corner going to bottom right corner and being able to move right and down - only. - -bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 50 -1.008913445455642e+29 -bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 25 -126410606437752.0 -bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 23 -8233430727600.0 -bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 15 -155117520.0 -bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 1 -2.0 - - >>> lattice_paths(25) - 126410606437752 - >>> lattice_paths(23) - 8233430727600 - >>> lattice_paths(20) - 137846528820 - >>> lattice_paths(15) - 155117520 - >>> lattice_paths(1) - 2 + Returns the number of paths possible in a n x n grid starting at top left + corner going to bottom right corner and being able to move right and down + only. + + bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 50 + 1.008913445455642e+29 + bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 25 + 126410606437752.0 + bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 23 + 8233430727600.0 + bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 15 + 155117520.0 + bruno@bruno-laptop:~/git/Python/project_euler/problem_15$ python3 sol1.py 1 + 2.0 + + >>> lattice_paths(25) + 126410606437752 + >>> lattice_paths(23) + 8233430727600 + >>> lattice_paths(20) + 137846528820 + >>> lattice_paths(15) + 155117520 + >>> lattice_paths(1) + 2 """ n = 2 * n # middle entry of odd rows starting at row 3 is the solution for n = 1, diff --git a/project_euler/problem_27/problem_27_sol1.py b/project_euler/problem_27/problem_27_sol1.py index 84b007a0bc88..e4833574c509 100644 --- a/project_euler/problem_27/problem_27_sol1.py +++ b/project_euler/problem_27/problem_27_sol1.py @@ -39,17 +39,17 @@ def is_prime(k: int) -> bool: def solution(a_limit: int, b_limit: int) -> int: """ - >>> solution(1000, 1000) - -59231 - >>> solution(200, 1000) - -59231 - >>> solution(200, 200) - -4925 - >>> solution(-1000, 1000) - 0 - >>> solution(-1000, -1000) - 0 - """ + >>> solution(1000, 1000) + -59231 + >>> solution(200, 1000) + -59231 + >>> solution(200, 200) + -4925 + >>> solution(-1000, 1000) + 0 + >>> solution(-1000, -1000) + 0 + """ longest = [0, 0, 0] # length, a, b for a in range((a_limit * -1) + 1, a_limit): for b in range(2, b_limit): diff --git a/project_euler/problem_56/sol1.py b/project_euler/problem_56/sol1.py index 2a00fa6a195d..98094ea8eb28 100644 --- a/project_euler/problem_56/sol1.py +++ b/project_euler/problem_56/sol1.py @@ -1,18 +1,18 @@ def maximum_digital_sum(a: int, b: int) -> int: """ - Considering natural numbers of the form, a**b, where a, b < 100, - what is the maximum digital sum? - :param a: - :param b: - :return: - >>> maximum_digital_sum(10,10) - 45 + Considering natural numbers of the form, a**b, where a, b < 100, + what is the maximum digital sum? + :param a: + :param b: + :return: + >>> maximum_digital_sum(10,10) + 45 - >>> maximum_digital_sum(100,100) - 972 + >>> maximum_digital_sum(100,100) + 972 - >>> maximum_digital_sum(100,200) - 1872 + >>> maximum_digital_sum(100,200) + 1872 """ # RETURN the MAXIMUM from the list of SUMs of the list of INT converted from STR of diff --git a/sorts/merge_sort.py b/sorts/merge_sort.py index 572f38a57029..4da29f32a36d 100644 --- a/sorts/merge_sort.py +++ b/sorts/merge_sort.py @@ -29,11 +29,13 @@ def merge(left: list, right: list) -> list: :param right: right collection :return: merge result """ + def _merge(): while left and right: yield (left if left[0] <= right[0] else right).pop(0) yield from left yield from right + return list(_merge()) if len(collection) <= 1: @@ -44,6 +46,7 @@ def _merge(): if __name__ == "__main__": import doctest + doctest.testmod() user_input = input("Enter numbers separated by a comma:\n").strip() unsorted = [int(item) for item in user_input.split(",")] diff --git a/sorts/recursive_bubble_sort.py b/sorts/recursive_bubble_sort.py index 79d706e6164d..82af89593e5b 100644 --- a/sorts/recursive_bubble_sort.py +++ b/sorts/recursive_bubble_sort.py @@ -1,41 +1,42 @@ -def bubble_sort(list1): +def bubble_sort(list_data: list, length: int = 0) -> list: """ It is similar is bubble sort but recursive. - :param list1: mutable ordered sequence of elements + :param list_data: mutable ordered sequence of elements + :param length: length of list data :return: the same list in ascending order - >>> bubble_sort([0, 5, 2, 3, 2]) + >>> bubble_sort([0, 5, 2, 3, 2], 5) [0, 2, 2, 3, 5] - >>> bubble_sort([]) + >>> bubble_sort([], 0) [] - >>> bubble_sort([-2, -45, -5]) + >>> bubble_sort([-2, -45, -5], 3) [-45, -5, -2] - >>> bubble_sort([-23, 0, 6, -4, 34]) + >>> bubble_sort([-23, 0, 6, -4, 34], 5) [-23, -4, 0, 6, 34] - >>> bubble_sort([-23, 0, 6, -4, 34]) == sorted([-23, 0, 6, -4, 34]) + >>> bubble_sort([-23, 0, 6, -4, 34], 5) == sorted([-23, 0, 6, -4, 34]) True - >>> bubble_sort(['z','a','y','b','x','c']) + >>> bubble_sort(['z','a','y','b','x','c'], 6) ['a', 'b', 'c', 'x', 'y', 'z'] + >>> bubble_sort([1.1, 3.3, 5.5, 7.7, 2.2, 4.4, 6.6]) + [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7] """ + length = length or len(list_data) + swapped = False + for i in range(length - 1): + if list_data[i] > list_data[i + 1]: + list_data[i], list_data[i + 1] = list_data[i + 1], list_data[i] + swapped = True - for i, num in enumerate(list1): - try: - if list1[i + 1] < num: - list1[i] = list1[i + 1] - list1[i + 1] = num - bubble_sort(list1) - except IndexError: - pass - return list1 + return list_data if not swapped else bubble_sort(list_data, length - 1) if __name__ == "__main__": - list1 = [33, 99, 22, 11, 66] - bubble_sort(list1) - print(list1) + import doctest + + doctest.testmod() diff --git a/strings/boyer_moore_search.py b/strings/boyer_moore_search.py index f340855d7a05..9d32a6943906 100644 --- a/strings/boyer_moore_search.py +++ b/strings/boyer_moore_search.py @@ -25,7 +25,7 @@ def __init__(self, text, pattern): self.textLen, self.patLen = len(text), len(pattern) def match_in_pattern(self, char): - """ finds the index of char in pattern in reverse order + """finds the index of char in pattern in reverse order Parameters : char (chr): character to be searched diff --git a/strings/capitalize.py b/strings/capitalize.py index 2a84a325bca4..63603aa07e2d 100644 --- a/strings/capitalize.py +++ b/strings/capitalize.py @@ -16,7 +16,7 @@ def capitalize(sentence: str) -> str: '' """ if not sentence: - return '' + return "" lower_to_upper = {lc: uc for lc, uc in zip(ascii_lowercase, ascii_uppercase)} return lower_to_upper.get(sentence[0], sentence[0]) + sentence[1:] diff --git a/traversals/binary_tree_traversals.py b/traversals/binary_tree_traversals.py index 7f100e66f200..50cdd5af72d3 100644 --- a/traversals/binary_tree_traversals.py +++ b/traversals/binary_tree_traversals.py @@ -53,11 +53,11 @@ def pre_order(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> pre_order(root) - 1 2 4 5 3 6 7 + 1,2,4,5,3,6,7, """ if not isinstance(node, TreeNode) or not node: return - print(node.data, end=" ") + print(node.data, end=",") pre_order(node.left) pre_order(node.right) @@ -75,12 +75,12 @@ def in_order(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> in_order(root) - 4 2 5 1 6 3 7 + 4,2,5,1,6,3,7, """ if not isinstance(node, TreeNode) or not node: return in_order(node.left) - print(node.data, end=" ") + print(node.data, end=",") in_order(node.right) @@ -97,13 +97,13 @@ def post_order(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> post_order(root) - 4 5 2 6 7 3 1 + 4,5,2,6,7,3,1, """ if not isinstance(node, TreeNode) or not node: return post_order(node.left) post_order(node.right) - print(node.data, end=" ") + print(node.data, end=",") def level_order(node: TreeNode) -> None: @@ -119,7 +119,7 @@ def level_order(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> level_order(root) - 1 2 3 4 5 6 7 + 1,2,3,4,5,6,7, """ if not isinstance(node, TreeNode) or not node: return @@ -127,7 +127,7 @@ def level_order(node: TreeNode) -> None: q.put(node) while not q.empty(): node_dequeued = q.get() - print(node_dequeued.data, end=" ") + print(node_dequeued.data, end=",") if node_dequeued.left: q.put(node_dequeued.left) if node_dequeued.right: @@ -146,10 +146,10 @@ def level_order_actual(node: TreeNode) -> None: >>> root.left, root.right = tree_node2, tree_node3 >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 - >>> level_order_actual(root) - 1 - 2 3 - 4 5 6 7 + >>> level_order_actual(root) + 1, + 2,3, + 4,5,6,7, """ if not isinstance(node, TreeNode) or not node: return @@ -159,7 +159,7 @@ def level_order_actual(node: TreeNode) -> None: list = [] while not q.empty(): node_dequeued = q.get() - print(node_dequeued.data, end=" ") + print(node_dequeued.data, end=",") if node_dequeued.left: list.append(node_dequeued.left) if node_dequeued.right: @@ -183,7 +183,7 @@ def pre_order_iter(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> pre_order_iter(root) - 1 2 4 5 3 6 7 + 1,2,4,5,3,6,7, """ if not isinstance(node, TreeNode) or not node: return @@ -191,7 +191,7 @@ def pre_order_iter(node: TreeNode) -> None: n = node while n or stack: while n: # start from root node, find its left child - print(n.data, end=" ") + print(n.data, end=",") stack.append(n) n = n.left # end of while means current node doesn't have left child @@ -213,7 +213,7 @@ def in_order_iter(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> in_order_iter(root) - 4 2 5 1 6 3 7 + 4,2,5,1,6,3,7, """ if not isinstance(node, TreeNode) or not node: return @@ -224,7 +224,7 @@ def in_order_iter(node: TreeNode) -> None: stack.append(n) n = n.left n = stack.pop() - print(n.data, end=" ") + print(n.data, end=",") n = n.right @@ -241,7 +241,7 @@ def post_order_iter(node: TreeNode) -> None: >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5 >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7 >>> post_order_iter(root) - 4 5 2 6 7 3 1 + 4,5,2,6,7,3,1, """ if not isinstance(node, TreeNode) or not node: return @@ -256,7 +256,7 @@ def post_order_iter(node: TreeNode) -> None: stack1.append(n.right) stack2.append(n) while stack2: # pop up from stack2 will be the post order - print(stack2.pop().data, end=" ") + print(stack2.pop().data, end=",") def prompt(s: str = "", width=50, char="*") -> str: From 696cd47e154e17c35520a734ff19d98b41f3f443 Mon Sep 17 00:00:00 2001 From: mohammadreza490 <47437328+mohammadreza490@users.noreply.github.com> Date: Thu, 10 Sep 2020 09:37:29 +0100 Subject: [PATCH 14/55] octal_to_decimal converter (#2399) * Create octal_to_decimal octal to decimal converter * Update octal_to_decimal * Update conversions/octal_to_decimal Co-authored-by: Christian Clauss Co-authored-by: Christian Clauss --- conversions/octal_to_decimal | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 conversions/octal_to_decimal diff --git a/conversions/octal_to_decimal b/conversions/octal_to_decimal new file mode 100644 index 000000000000..a5b027e3ae8d --- /dev/null +++ b/conversions/octal_to_decimal @@ -0,0 +1,37 @@ +def oct_to_decimal(oct_string: str) -> int: + """ + Convert a octal value to its decimal equivalent + + >>> oct_to_decimal("12") + 10 + >>> oct_to_decimal(" 12 ") + 10 + >>> oct_to_decimal("-45") + -37 + >>> oct_to_decimal("2-0Fm") + ValueError: Non-octal value was passed to the function + >>> oct_to_decimal("") + ValueError: Empty string value was passed to the function + >>> oct_to_decimal("19") + ValueError: Non-octal value was passed to the function + """ + oct_string = str(oct_string).strip() + if not oct_string: + raise ValueError("Empty string was passed to the function") + is_negative = oct_string[0] == "-" + if is_negative: + oct_string = oct_string[1:] + if not all(0 <= int(char) <= 7 for char in oct_string): + raise ValueError("Non-octal value was passed to the function") + decimal_number = 0 + for char in oct_string: + decimal_number = 8 * decimal_number + int(char) + if is_negative: + decimal_number = -decimal_number + return decimal_number + + +if __name__ == "__main__": + from doctest import testmod + + testmod() From 1b3fec3f1f483f09e277a105e0708a41c56e5006 Mon Sep 17 00:00:00 2001 From: mohammadreza490 <47437328+mohammadreza490@users.noreply.github.com> Date: Fri, 11 Sep 2020 05:16:43 +0100 Subject: [PATCH 15/55] binary_to_decimal converter (#2400) * Create binary_to_decimal binary to decimal converter * Update conversions/binary_to_decimal Co-authored-by: Christian Clauss * Update binary_to_decimal * Update conversions/binary_to_decimal Co-authored-by: Christian Clauss * Update binary_to_decimal Co-authored-by: Christian Clauss --- conversions/binary_to_decimal | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 conversions/binary_to_decimal diff --git a/conversions/binary_to_decimal b/conversions/binary_to_decimal new file mode 100644 index 000000000000..1f223daf825f --- /dev/null +++ b/conversions/binary_to_decimal @@ -0,0 +1,39 @@ +def bin_to_decimal(bin_string: str) -> int: + """ + Convert a binary value to its decimal equivalent + + >>> bin_to_decimal("101") + 5 + >>> bin_to_decimal(" 1010 ") + 10 + >>> bin_to_decimal("-11101") + -29 + >>> bin_to_decimal("0") + 0 + >>> bin_to_decimal("a") + ValueError: Non-binary value was passed to the function + >>> bin_to_decimal("") + ValueError: Empty string value was passed to the function + >>> bin_to_decimal("39") + ValueError: Non-binary value was passed to the function + """ + bin_string = str(bin_string).strip() + if not bin_string: + raise ValueError("Empty string was passed to the function") + is_negative = bin_string[0] == "-" + if is_negative: + bin_string = bin_string[1:] + if not all(char in "01" for char in bin_string): + raise ValueError("Non-binary value was passed to the function") + decimal_number = 0 + for char in bin_string: + decimal_number = 2 * decimal_number + int(char) + if is_negative: + decimal_number = -decimal_number + return decimal_number + + +if __name__ == "__main__": + from doctest import testmod + + testmod() From a191f89fe21a8c092b152799d40669dd52eec940 Mon Sep 17 00:00:00 2001 From: Marcos Cannabrava <54267712+marcoscannabrava@users.noreply.github.com> Date: Fri, 11 Sep 2020 11:23:26 -0300 Subject: [PATCH 16/55] Fix Non Recursive Depth First Search (#2207) * Fix Non Recursive Depth First Search * Unindent docstring * Reindent docstring by 1 space Co-authored-by: Christian Clauss Co-authored-by: Christian Clauss --- graphs/depth_first_search.py | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/graphs/depth_first_search.py b/graphs/depth_first_search.py index 9ec7083c7fc1..fee9ea07728d 100644 --- a/graphs/depth_first_search.py +++ b/graphs/depth_first_search.py @@ -1,24 +1,12 @@ -"""The DFS function simply calls itself recursively for every unvisited child of -its argument. We can emulate that behaviour precisely using a stack of iterators. -Instead of recursively calling with a node, we'll push an iterator to the node's -children onto the iterator stack. When the iterator at the top of the stack -terminates, we'll pop it off the stack. - -Pseudocode: - all nodes initially unexplored - mark s as explored - for every edge (s, v): - if v unexplored: - DFS(G, v) -""" -from typing import Dict, Set +"""Non recursive implementation of a DFS algorithm.""" + +from typing import Set, Dict def depth_first_search(graph: Dict, start: str) -> Set[int]: """Depth First Search on Graph - :param graph: directed graph in dictionary format - :param vertex: starting vectex as a string + :param vertex: starting vertex as a string :returns: the trace of the search >>> G = { "A": ["B", "C", "D"], "B": ["A", "D", "E"], ... "C": ["A", "F"], "D": ["B", "D"], "E": ["B", "F"], @@ -31,13 +19,16 @@ def depth_first_search(graph: Dict, start: str) -> Set[int]: True """ explored, stack = set(start), [start] + while stack: v = stack.pop() - # one difference from BFS is to pop last element here instead of first one - for w in graph[v]: - if w not in explored: - explored.add(w) - stack.append(w) + explored.add(v) + # Differences from BFS: + # 1) pop last element instead of first one + # 2) add adjacent elements to stack without exploring them + for adj in reversed(graph[v]): + if adj not in explored: + stack.append(adj) return explored From c6769560301ccff2b606d19ae440136b47482cf8 Mon Sep 17 00:00:00 2001 From: Santosh Mohan Rajkumar Date: Sat, 12 Sep 2020 01:55:05 +0530 Subject: [PATCH 17/55] lxmlCovidDataFetch (#2416) * lxmlCovidDataFetch * lxmlCovidDataFetch1 * Update worldometers_covid_with_lxml.py * Rename worldometers_covid_with_lxml.py to covid_stats_via_xpath.py Co-authored-by: Christian Clauss --- web_programming/covid_stats_via_xpath.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 web_programming/covid_stats_via_xpath.py diff --git a/web_programming/covid_stats_via_xpath.py b/web_programming/covid_stats_via_xpath.py new file mode 100644 index 000000000000..d22ed017878c --- /dev/null +++ b/web_programming/covid_stats_via_xpath.py @@ -0,0 +1,23 @@ +""" +This is to show simple COVID19 info fetching from worldometers site using lxml +* The main motivation to use lxml in place of bs4 is that it is faster and therefore +more convenient to use in Python web projects (e.g. Django or Flask-based) +""" + +from collections import namedtuple + +import requests +from lxml import html + +covid_data = namedtuple("covid_data", "cases deaths recovered") + + +def covid_stats(url: str = "https://www.worldometers.info/coronavirus/") -> covid_data: + xpath_str = '//div[@class = "maincounter-number"]/span/text()' + return covid_data(*html.fromstring(requests.get(url).content).xpath(xpath_str)) + + +fmt = """Total COVID-19 cases in the world: {} +Total deaths due to COVID-19 in the world: {} +Total COVID-19 patients recovered in the world: {}""" +print(fmt.format(*covid_stats())) From 2e790ce4caf8f40ec54bff06ec857c2bb777e7be Mon Sep 17 00:00:00 2001 From: Meysam Date: Sat, 12 Sep 2020 01:43:43 +0430 Subject: [PATCH 18/55] file-transfer: writing tests and ensuring that all is going well (#2413) * file-transfer: writing tests and ensuring that all is going well * def send_file(filename: str = "mytext.txt", testing: bool = False) -> None: * send_file(filename="mytext.txt", testing=True) * Update send_file.py * requirements.txt: lxml Co-authored-by: Christian Clauss --- file_transfer/send_file.py | 17 ++++++-------- file_transfer/tests/test_send_file.py | 32 +++++++++++++++++++++++++++ requirements.txt | 1 + 3 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 file_transfer/tests/test_send_file.py diff --git a/file_transfer/send_file.py b/file_transfer/send_file.py index 6494114a9072..5b53471dfb50 100644 --- a/file_transfer/send_file.py +++ b/file_transfer/send_file.py @@ -1,11 +1,6 @@ -if __name__ == "__main__": - import socket # Import socket module - - ONE_CONNECTION_ONLY = ( - True # Set this to False if you wish to continuously accept connections - ) +def send_file(filename: str = "mytext.txt", testing: bool = False) -> None: + import socket - filename = "mytext.txt" port = 12312 # Reserve a port for your service. sock = socket.socket() # Create a socket object host = socket.gethostname() # Get local machine name @@ -29,10 +24,12 @@ print("Done sending") conn.close() - if ( - ONE_CONNECTION_ONLY - ): # This is to make sure that the program doesn't hang while testing + if testing: # Allow the test to complete break sock.shutdown(1) sock.close() + + +if __name__ == "__main__": + send_file() diff --git a/file_transfer/tests/test_send_file.py b/file_transfer/tests/test_send_file.py new file mode 100644 index 000000000000..170c2c0aed09 --- /dev/null +++ b/file_transfer/tests/test_send_file.py @@ -0,0 +1,32 @@ +from unittest.mock import patch, Mock + + +from file_transfer.send_file import send_file + + +@patch("socket.socket") +@patch("builtins.open") +def test_send_file_running_as_expected(file, sock): + # ===== initialization ===== + conn = Mock() + sock.return_value.accept.return_value = conn, Mock() + f = iter([1, None]) + file.return_value.__enter__.return_value.read.side_effect = lambda _: next(f) + + # ===== invoke ===== + send_file(filename="mytext.txt", testing=True) + + # ===== ensurance ===== + sock.assert_called_once() + sock.return_value.bind.assert_called_once() + sock.return_value.listen.assert_called_once() + sock.return_value.accept.assert_called_once() + conn.recv.assert_called_once() + + file.return_value.__enter__.assert_called_once() + file.return_value.__enter__.return_value.read.assert_called() + + conn.send.assert_called_once() + conn.close.assert_called_once() + sock.return_value.shutdown.assert_called_once() + sock.return_value.close.assert_called_once() diff --git a/requirements.txt b/requirements.txt index 8362afc62509..b070ffdf611d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ black fake_useragent flake8 keras +lxml matplotlib mypy numpy From f754c0d31ffe9a6be990fecbc32c55fa97271d9c Mon Sep 17 00:00:00 2001 From: Guillaume Rochedix <33205665+BriseBalloches@users.noreply.github.com> Date: Sat, 12 Sep 2020 07:50:12 +0200 Subject: [PATCH 19/55] Jump search (#2415) * jump_search: doctest, docstring, type hint, inputs * jumpsearch.py: case number not found * trailing whitespace jump search --- searches/jump_search.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/searches/jump_search.py b/searches/jump_search.py index 5ba80e9d35be..31a9656c55fe 100644 --- a/searches/jump_search.py +++ b/searches/jump_search.py @@ -1,7 +1,28 @@ +""" +Pure Python implementation of the jump search algorithm. +This algorithm iterates through a sorted collection with a step of n^(1/2), +until the element compared is bigger than the one searched. +It will then perform a linear search until it matches the wanted number. +If not found, it returns -1. +""" + import math -def jump_search(arr, x): +def jump_search(arr: list, x: int) -> int: + """ + Pure Python implementation of the jump search algorithm. + Examples: + >>> jump_search([0, 1, 2, 3, 4, 5], 3) + 3 + >>> jump_search([-5, -2, -1], -1) + 2 + >>> jump_search([0, 5, 10, 20], 8) + -1 + >>> jump_search([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610], 55) + 10 + """ + n = len(arr) step = int(math.floor(math.sqrt(n))) prev = 0 @@ -21,6 +42,11 @@ def jump_search(arr, x): if __name__ == "__main__": - arr = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] - x = 55 - print(f"Number {x} is at index {jump_search(arr, x)}") + user_input = input("Enter numbers separated by a comma:\n").strip() + arr = [int(item) for item in user_input.split(",")] + x = int(input("Enter the number to be searched:\n")) + res = jump_search(arr, x) + if res == -1: + print("Number not found!") + else: + print(f"Number {x} is at index {res}") From 20e98fcded341d5aef6dfdfc5cdac431a55252bd Mon Sep 17 00:00:00 2001 From: Hasenn Date: Sun, 13 Sep 2020 10:11:27 +0200 Subject: [PATCH 20/55] Fix some warnings from LGTM (#2420) * fix assignment of a variable to itself * Fix unnecessary 'else' clause in loop * formatting and redundant reasignment fix * mark unreachable code with a TODO comment * fix variable defined multiple times * fix static method without static decorator * revert unintended autoformatting Co-authored-by: Christian Clauss * revert autoformatting issue * applied black autoformatting Co-authored-by: Christian Clauss --- ciphers/enigma_machine2.py | 1 - graphs/directed_and_undirected_(weighted)_graph.py | 3 +++ graphs/minimum_spanning_tree_boruvka.py | 1 + maths/chudnovsky_algorithm.py | 1 - other/triplet_sum.py | 3 +-- scheduling/shortest_job_first.py | 6 ++++-- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ciphers/enigma_machine2.py b/ciphers/enigma_machine2.py index 0fbe97284d38..4344db0056fd 100644 --- a/ciphers/enigma_machine2.py +++ b/ciphers/enigma_machine2.py @@ -218,7 +218,6 @@ def enigma( rotorpos1 -= 1 rotorpos2 -= 1 rotorpos3 -= 1 - plugboard = plugboard result = [] diff --git a/graphs/directed_and_undirected_(weighted)_graph.py b/graphs/directed_and_undirected_(weighted)_graph.py index 61e196adfaac..5cfa9e13edd9 100644 --- a/graphs/directed_and_undirected_(weighted)_graph.py +++ b/graphs/directed_and_undirected_(weighted)_graph.py @@ -226,6 +226,7 @@ def has_cycle(self): break else: return True + # TODO:The following code is unreachable. anticipating_nodes.add(stack[len_stack_minus_one]) len_stack_minus_one -= 1 if visited.count(node[1]) < 1: @@ -453,6 +454,8 @@ def has_cycle(self): break else: return True + # TODO: the following code is unreachable + # is this meant to be called in the else ? anticipating_nodes.add(stack[len_stack_minus_one]) len_stack_minus_one -= 1 if visited.count(node[1]) < 1: diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index f65aa7cef031..3b05f94b5140 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -146,6 +146,7 @@ def union(self, item1, item2): self.parent[root2] = root1 return root1 + @staticmethod def boruvka_mst(graph): """ Implementation of Boruvka's algorithm diff --git a/maths/chudnovsky_algorithm.py b/maths/chudnovsky_algorithm.py index fb188cd6a3d8..aaee7462822e 100644 --- a/maths/chudnovsky_algorithm.py +++ b/maths/chudnovsky_algorithm.py @@ -44,7 +44,6 @@ def pi(precision: int) -> str: getcontext().prec = precision num_iterations = ceil(precision / 14) constant_term = 426880 * Decimal(10005).sqrt() - multinomial_term = 1 exponential_term = 1 linear_term = 13591409 partial_sum = Decimal(linear_term) diff --git a/other/triplet_sum.py b/other/triplet_sum.py index 247e3bb1618d..25fed5d54579 100644 --- a/other/triplet_sum.py +++ b/other/triplet_sum.py @@ -61,8 +61,7 @@ def triplet_sum2(arr: List[int], target: int) -> Tuple[int, int, int]: left += 1 elif arr[i] + arr[left] + arr[right] > target: right -= 1 - else: - return (0, 0, 0) + return (0, 0, 0) def solution_times() -> Tuple[float, float]: diff --git a/scheduling/shortest_job_first.py b/scheduling/shortest_job_first.py index 6a2fdeeecc5a..ecb6e01fdfe6 100644 --- a/scheduling/shortest_job_first.py +++ b/scheduling/shortest_job_first.py @@ -11,7 +11,6 @@ def calculate_waitingtime( arrival_time: List[int], burst_time: List[int], no_of_processes: int ) -> List[int]: - """ Calculate the waiting time of each processes Return: list of waiting times. @@ -126,13 +125,16 @@ def calculate_average_times( for i in range(no_of_processes): print("Enter the arrival time and brust time for process:--" + str(i + 1)) arrival_time[i], burst_time[i] = map(int, input().split()) + waiting_time = calculate_waitingtime(arrival_time, burst_time, no_of_processes) + bt = burst_time n = no_of_processes wt = waiting_time turn_around_time = calculate_turnaroundtime(bt, n, wt) + calculate_average_times(waiting_time, turn_around_time, no_of_processes) - processes = list(range(1, no_of_processes + 1)) + fcfs = pd.DataFrame( list(zip(processes, burst_time, arrival_time, waiting_time, turn_around_time)), columns=[ From d6bff5c1331864ab41d387896582f422322ca80d Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Sun, 13 Sep 2020 19:27:20 +0800 Subject: [PATCH 21/55] Renamed files and fixed Doctest (#2421) * * Renamed files * Fiexed doctest * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- .../{binary_to_decimal => binary_to_decimal.py} | 12 ++++++++---- ...ecimal_to_decimal => hexadecimal_to_decimal.py} | 14 +++++++++----- file_transfer/tests/test_send_file.py | 3 +-- graphs/depth_first_search.py | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) rename conversions/{binary_to_decimal => binary_to_decimal.py} (79%) rename conversions/{hexadecimal_to_decimal => hexadecimal_to_decimal.py} (81%) diff --git a/conversions/binary_to_decimal b/conversions/binary_to_decimal.py similarity index 79% rename from conversions/binary_to_decimal rename to conversions/binary_to_decimal.py index 1f223daf825f..a7625e475bdc 100644 --- a/conversions/binary_to_decimal +++ b/conversions/binary_to_decimal.py @@ -11,10 +11,16 @@ def bin_to_decimal(bin_string: str) -> int: >>> bin_to_decimal("0") 0 >>> bin_to_decimal("a") + Traceback (most recent call last): + ... ValueError: Non-binary value was passed to the function >>> bin_to_decimal("") - ValueError: Empty string value was passed to the function + Traceback (most recent call last): + ... + ValueError: Empty string was passed to the function >>> bin_to_decimal("39") + Traceback (most recent call last): + ... ValueError: Non-binary value was passed to the function """ bin_string = str(bin_string).strip() @@ -28,9 +34,7 @@ def bin_to_decimal(bin_string: str) -> int: decimal_number = 0 for char in bin_string: decimal_number = 2 * decimal_number + int(char) - if is_negative: - decimal_number = -decimal_number - return decimal_number + return -decimal_number if is_negative else decimal_number if __name__ == "__main__": diff --git a/conversions/hexadecimal_to_decimal b/conversions/hexadecimal_to_decimal.py similarity index 81% rename from conversions/hexadecimal_to_decimal rename to conversions/hexadecimal_to_decimal.py index e87caa0f4787..beb1c2c3ded6 100644 --- a/conversions/hexadecimal_to_decimal +++ b/conversions/hexadecimal_to_decimal.py @@ -17,14 +17,20 @@ def hex_to_decimal(hex_string: str) -> int: >>> hex_to_decimal("-Ff") -255 >>> hex_to_decimal("F-f") + Traceback (most recent call last): + ... ValueError: Non-hexadecimal value was passed to the function >>> hex_to_decimal("") - ValueError: Empty string value was passed to the function + Traceback (most recent call last): + ... + ValueError: Empty string was passed to the function >>> hex_to_decimal("12m") + Traceback (most recent call last): + ... ValueError: Non-hexadecimal value was passed to the function """ hex_string = hex_string.strip().lower() - if not hex_string: + if not hex_string: raise ValueError("Empty string was passed to the function") is_negative = hex_string[0] == "-" if is_negative: @@ -34,9 +40,7 @@ def hex_to_decimal(hex_string: str) -> int: decimal_number = 0 for char in hex_string: decimal_number = 16 * decimal_number + hex_table[char] - if is_negative: - decimal_number = -decimal_number - return decimal_number + return -decimal_number if is_negative else decimal_number if __name__ == "__main__": diff --git a/file_transfer/tests/test_send_file.py b/file_transfer/tests/test_send_file.py index 170c2c0aed09..2a6008448362 100644 --- a/file_transfer/tests/test_send_file.py +++ b/file_transfer/tests/test_send_file.py @@ -1,5 +1,4 @@ -from unittest.mock import patch, Mock - +from unittest.mock import Mock, patch from file_transfer.send_file import send_file diff --git a/graphs/depth_first_search.py b/graphs/depth_first_search.py index fee9ea07728d..43f2eaaea19a 100644 --- a/graphs/depth_first_search.py +++ b/graphs/depth_first_search.py @@ -1,6 +1,6 @@ """Non recursive implementation of a DFS algorithm.""" -from typing import Set, Dict +from typing import Dict, Set def depth_first_search(graph: Dict, start: str) -> Set[int]: From 44b8cb0c81b1c86dc8957d6d218f3643488e84a9 Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Sun, 13 Sep 2020 19:56:03 +0800 Subject: [PATCH 22/55] Updated Stack (#2414) * * Added type hints * Added test * Formated code * updating DIRECTORY.md * Update stack.py * Test error conditions for pop, peek, and Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Christian Clauss --- DIRECTORY.md | 20 +++++++- data_structures/stacks/stack.py | 87 ++++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 30 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 70f7726d99c0..ac10afdc0ccd 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -24,6 +24,9 @@ * [Sudoku](https://github.com/TheAlgorithms/Python/blob/master/backtracking/sudoku.py) * [Sum Of Subsets](https://github.com/TheAlgorithms/Python/blob/master/backtracking/sum_of_subsets.py) +## Bit Manipulation + * [Binary Or Operator](https://github.com/TheAlgorithms/Python/blob/master/bit_manipulation/binary_or_operator.py) + ## Blockchain * [Chinese Remainder Theorem](https://github.com/TheAlgorithms/Python/blob/master/blockchain/chinese_remainder_theorem.py) * [Diophantine Equation](https://github.com/TheAlgorithms/Python/blob/master/blockchain/diophantine_equation.py) @@ -50,6 +53,7 @@ * [Deterministic Miller Rabin](https://github.com/TheAlgorithms/Python/blob/master/ciphers/deterministic_miller_rabin.py) * [Diffie](https://github.com/TheAlgorithms/Python/blob/master/ciphers/diffie.py) * [Elgamal Key Generator](https://github.com/TheAlgorithms/Python/blob/master/ciphers/elgamal_key_generator.py) + * [Enigma Machine2](https://github.com/TheAlgorithms/Python/blob/master/ciphers/enigma_machine2.py) * [Hill Cipher](https://github.com/TheAlgorithms/Python/blob/master/ciphers/hill_cipher.py) * [Mixed Keyword Cypher](https://github.com/TheAlgorithms/Python/blob/master/ciphers/mixed_keyword_cypher.py) * [Morse Code Implementation](https://github.com/TheAlgorithms/Python/blob/master/ciphers/morse_code_implementation.py) @@ -105,6 +109,7 @@ * [Segment Tree Other](https://github.com/TheAlgorithms/Python/blob/master/data_structures/binary_tree/segment_tree_other.py) * [Treap](https://github.com/TheAlgorithms/Python/blob/master/data_structures/binary_tree/treap.py) * Disjoint Set + * [Alternate Disjoint Set](https://github.com/TheAlgorithms/Python/blob/master/data_structures/disjoint_set/alternate_disjoint_set.py) * [Disjoint Set](https://github.com/TheAlgorithms/Python/blob/master/data_structures/disjoint_set/disjoint_set.py) * Hashing * [Double Hash](https://github.com/TheAlgorithms/Python/blob/master/data_structures/hashing/double_hash.py) @@ -419,6 +424,7 @@ * [Sum Of Geometric Progression](https://github.com/TheAlgorithms/Python/blob/master/maths/sum_of_geometric_progression.py) * [Test Prime Check](https://github.com/TheAlgorithms/Python/blob/master/maths/test_prime_check.py) * [Trapezoidal Rule](https://github.com/TheAlgorithms/Python/blob/master/maths/trapezoidal_rule.py) + * [Ugly Numbers](https://github.com/TheAlgorithms/Python/blob/master/maths/ugly_numbers.py) * [Volume](https://github.com/TheAlgorithms/Python/blob/master/maths/volume.py) * [Zellers Congruence](https://github.com/TheAlgorithms/Python/blob/master/maths/zellers_congruence.py) @@ -474,6 +480,7 @@ * [Sdes](https://github.com/TheAlgorithms/Python/blob/master/other/sdes.py) * [Sierpinski Triangle](https://github.com/TheAlgorithms/Python/blob/master/other/sierpinski_triangle.py) * [Tower Of Hanoi](https://github.com/TheAlgorithms/Python/blob/master/other/tower_of_hanoi.py) + * [Triplet Sum](https://github.com/TheAlgorithms/Python/blob/master/other/triplet_sum.py) * [Two Sum](https://github.com/TheAlgorithms/Python/blob/master/other/two_sum.py) * [Word Patterns](https://github.com/TheAlgorithms/Python/blob/master/other/word_patterns.py) @@ -600,6 +607,12 @@ * [Solution42](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_42/solution42.py) * Problem 43 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_43/sol1.py) + * Problem 44 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_44/sol1.py) + * Problem 45 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_45/sol1.py) + * Problem 46 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_46/sol1.py) * Problem 47 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_47/sol1.py) * Problem 48 @@ -608,10 +621,14 @@ * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_52/sol1.py) * Problem 53 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_53/sol1.py) + * Problem 55 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_55/sol1.py) * Problem 551 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_551/sol1.py) * Problem 56 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_56/sol1.py) + * Problem 63 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_63/sol1.py) * Problem 67 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_67/sol1.py) * Problem 76 @@ -673,7 +690,6 @@ * [Recursive Insertion Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/recursive_insertion_sort.py) * [Selection Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/selection_sort.py) * [Shell Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/shell_sort.py) - * [Sleep Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/sleep_sort.py) * [Stooge Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/stooge_sort.py) * [Strand Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/strand_sort.py) * [Tim Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/tim_sort.py) @@ -685,6 +701,7 @@ ## Strings * [Aho-Corasick](https://github.com/TheAlgorithms/Python/blob/master/strings/aho-corasick.py) * [Boyer Moore Search](https://github.com/TheAlgorithms/Python/blob/master/strings/boyer_moore_search.py) + * [Capitalize](https://github.com/TheAlgorithms/Python/blob/master/strings/capitalize.py) * [Check Anagrams](https://github.com/TheAlgorithms/Python/blob/master/strings/check_anagrams.py) * [Check Pangram](https://github.com/TheAlgorithms/Python/blob/master/strings/check_pangram.py) * [Is Palindrome](https://github.com/TheAlgorithms/Python/blob/master/strings/is_palindrome.py) @@ -715,6 +732,7 @@ * [Emails From Url](https://github.com/TheAlgorithms/Python/blob/master/web_programming/emails_from_url.py) * [Fetch Bbc News](https://github.com/TheAlgorithms/Python/blob/master/web_programming/fetch_bbc_news.py) * [Fetch Github Info](https://github.com/TheAlgorithms/Python/blob/master/web_programming/fetch_github_info.py) + * [Fetch Jobs](https://github.com/TheAlgorithms/Python/blob/master/web_programming/fetch_jobs.py) * [Get Imdb Top 250 Movies Csv](https://github.com/TheAlgorithms/Python/blob/master/web_programming/get_imdb_top_250_movies_csv.py) * [Get Imdbtop](https://github.com/TheAlgorithms/Python/blob/master/web_programming/get_imdbtop.py) * [Slack Message](https://github.com/TheAlgorithms/Python/blob/master/web_programming/slack_message.py) diff --git a/data_structures/stacks/stack.py b/data_structures/stacks/stack.py index a4bcb5beabd4..840cde099d38 100644 --- a/data_structures/stacks/stack.py +++ b/data_structures/stacks/stack.py @@ -1,4 +1,5 @@ -__author__ = "Omkar Pathak" +class StackOverflowError(BaseException): + pass class Stack: @@ -7,18 +8,17 @@ class Stack: element to the top of the stack, and pop() removes an element from the top of a stack. The order in which elements come off of a stack are Last In, First Out (LIFO). - https://en.wikipedia.org/wiki/Stack_(abstract_data_type) """ - def __init__(self, limit=10): + def __init__(self, limit: int = 10): self.stack = [] self.limit = limit - def __bool__(self): + def __bool__(self) -> bool: return bool(self.stack) - def __str__(self): + def __str__(self) -> str: return str(self.stack) def push(self, data): @@ -29,21 +29,20 @@ def push(self, data): def pop(self): """ Pop an element off of the top of the stack.""" - if self.stack: - return self.stack.pop() - else: - raise IndexError("pop from an empty stack") + return self.stack.pop() def peek(self): """ Peek at the top-most element of the stack.""" - if self.stack: - return self.stack[-1] + return self.stack[-1] - def is_empty(self): + def is_empty(self) -> bool: """ Check if a stack is empty.""" return not bool(self.stack) - def size(self): + def is_full(self) -> bool: + return self.size() == self.limit + + def size(self) -> int: """ Return the size of the stack.""" return len(self.stack) @@ -52,24 +51,54 @@ def __contains__(self, item) -> bool: return item in self.stack -class StackOverflowError(BaseException): - pass - +def test_stack() -> None: + """ + >>> test_stack() + """ + stack = Stack(10) + assert bool(stack) is False + assert stack.is_empty() is True + assert stack.is_full() is False + assert str(stack) == "[]" + + try: + _ = stack.pop() + assert False # This should not happen + except IndexError: + assert True # This should happen + + try: + _ = stack.peek() + assert False # This should not happen + except IndexError: + assert True # This should happen -if __name__ == "__main__": - stack = Stack() for i in range(10): + assert stack.size() == i stack.push(i) - print("Stack demonstration:\n") - print("Initial stack: " + str(stack)) - print("pop(): " + str(stack.pop())) - print("After pop(), the stack is now: " + str(stack)) - print("peek(): " + str(stack.peek())) + assert bool(stack) is True + assert stack.is_empty() is False + assert stack.is_full() is True + assert str(stack) == str(list(range(10))) + assert stack.pop() == 9 + assert stack.peek() == 8 + stack.push(100) - print("After push(100), the stack is now: " + str(stack)) - print("is_empty(): " + str(stack.is_empty())) - print("size(): " + str(stack.size())) - num = 5 - if num in stack: - print(f"{num} is in stack") + assert str(stack) == str([0, 1, 2, 3, 4, 5, 6, 7, 8, 100]) + + try: + stack.push(200) + assert False # This should not happen + except StackOverflowError: + assert True # This should happen + + assert stack.is_empty() is False + assert stack.size() == 10 + + assert 5 in stack + assert 55 not in stack + + +if __name__ == "__main__": + test_stack() From 4e5b730e85ce02b05dc3fe1a862bc33bc29b6a73 Mon Sep 17 00:00:00 2001 From: Santosh Mohan Rajkumar Date: Mon, 14 Sep 2020 01:56:15 +0530 Subject: [PATCH 23/55] recaptchaVerification (#2417) * recaptchaVerification * recaptchaVerification * recaptchaVerification1 * recaptchaVerification2 * recaptchaVerification3 * recaptchaVerification4 * recaptchaVerificatio5 * recaptchaVerificatio5 * recaptchaVerificatio6 * drawOnVideoStreamOpenCV * matrixInverseMCAmethod * fixingImports * recaptchaVerificationfixes * recaptchaVerificationfixes * recaptchaVerificationfixes * recaptchaVerificationfixes * recaptchaVerificationfixes1 * recaptchaVerificationfixes1 * authenticate = login = render = redirect = print Co-authored-by: Christian Clauss --- web_programming/recaptcha_verification.py | 66 +++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 web_programming/recaptcha_verification.py diff --git a/web_programming/recaptcha_verification.py b/web_programming/recaptcha_verification.py new file mode 100644 index 000000000000..47c6c42f2ad0 --- /dev/null +++ b/web_programming/recaptcha_verification.py @@ -0,0 +1,66 @@ +""" +Recaptcha is a free captcha service offered by Google in order to secure websites and +forms. At https://www.google.com/recaptcha/admin/create you can create new recaptcha +keys and see the keys that your have already created. +* Keep in mind that recaptcha doesn't work with localhost +When you create a recaptcha key, your will get two separate keys: ClientKey & SecretKey. +ClientKey should be kept in your site's front end +SecretKey should be kept in your site's back end + +# An example HTML login form with recaptcha tag is shown below + +
+

Log in

+ {% csrf_token %} +
+ +
+
+ +
+
+ +
+ +
+
+ + + + +Below a Django function for the views.py file contains a login form for demonstrating +recaptcha verification. +""" +import requests + +try: + from django.contrib.auth import authenticate, login + from django.shortcuts import redirect, render +except ImportError: + authenticate = login = render = redirect = print + + +def login_using_recaptcha(request): + # Enter your recaptcha secret key here + secret_key = "secretKey" + url = "https://www.google.com/recaptcha/api/siteverify" + + # when method is not POST, direct user to login page + if request.method != "POST": + return render(request, "login.html") + + # from the frontend, get username, password, and client_key + username = request.POST.get("username") + password = request.POST.get("password") + client_key = request.POST.get("g-recaptcha-response") + + # post recaptcha response to Google's recaptcha api + response = requests.post(url, data={"secret": secret_key, "response": client_key}) + # if the recaptcha api verified our keys + if response.json().get("success", False): + # authenticate the user + user_in_database = authenticate(request, username=username, password=password) + if user_in_database: + login(request, user_in_database) + return redirect("/your-webpage") + return render(request, "login.html") From 799fde4c07dd039807ffb5020824fc065728b17a Mon Sep 17 00:00:00 2001 From: Ashley Jeji George <40469421+Ashley-J-George@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:14:46 +0530 Subject: [PATCH 24/55] Update linear_search.py (#2422) * Update linear_search.py Python implementation of recursive linear search algorithm * Update linear_search.py Added different doctests Added the parameter hints Handled the exception * Update linear_search.py added parameter hints to linear_search * Update linear_search.py Both the functions return the index if the target is found and -1 if it is not found The rec_linear_search raises an exception if there is an indexing problem Made changes in the doc comments * Update linear_search.py Co-authored-by: Christian Clauss --- searches/linear_search.py | 58 ++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/searches/linear_search.py b/searches/linear_search.py index 2056bd7a4916..777080d14e36 100644 --- a/searches/linear_search.py +++ b/searches/linear_search.py @@ -2,17 +2,15 @@ This is pure Python implementation of linear search algorithm For doctests run following command: -python -m doctest -v linear_search.py -or python3 -m doctest -v linear_search.py For manual testing run: -python linear_search.py +python3 linear_search.py """ -def linear_search(sequence, target): - """Pure implementation of linear search algorithm in Python +def linear_search(sequence: list, target: int) -> int: + """A pure Python implementation of a linear search algorithm :param sequence: a collection with comparable items (as sorted items not required in Linear Search) @@ -22,30 +20,58 @@ def linear_search(sequence, target): Examples: >>> linear_search([0, 5, 7, 10, 15], 0) 0 - >>> linear_search([0, 5, 7, 10, 15], 15) 4 - >>> linear_search([0, 5, 7, 10, 15], 5) 1 - >>> linear_search([0, 5, 7, 10, 15], 6) - + -1 """ for index, item in enumerate(sequence): if item == target: return index - return None + return -1 + + +def rec_linear_search(sequence: list, low: int, high: int, target: int) -> int: + """ + A pure Python implementation of a recursive linear search algorithm + + :param sequence: a collection with comparable items (as sorted items not required + in Linear Search) + :param low: Lower bound of the array + :param high: Higher bound of the array + :param target: The element to be found + :return: Index of the key or -1 if key not found + + Examples: + >>> rec_linear_search([0, 30, 500, 100, 700], 0, 4, 0) + 0 + >>> rec_linear_search([0, 30, 500, 100, 700], 0, 4, 700) + 4 + >>> rec_linear_search([0, 30, 500, 100, 700], 0, 4, 30) + 1 + >>> rec_linear_search([0, 30, 500, 100, 700], 0, 4, -6) + -1 + """ + if not (0 <= high < len(sequence) and 0 <= low < len(sequence)): + raise Exception("Invalid upper or lower bound!") + if high < low: + return -1 + if sequence[low] == target: + return low + if sequence[high] == target: + return high + return rec_linear_search(sequence, low + 1, high - 1, target) if __name__ == "__main__": user_input = input("Enter numbers separated by comma:\n").strip() - sequence = [int(item) for item in user_input.split(",")] + sequence = [int(item.strip()) for item in user_input.split(",")] - target_input = input("Enter a single number to be found in the list:\n") - target = int(target_input) + target = int(input("Enter a single number to be found in the list:\n").strip()) result = linear_search(sequence, target) - if result is not None: - print(f"{target} found at position : {result}") + if result != -1: + print(f"linear_search({sequence}, {target}) = {result}") else: - print("Not found") + print(f"{target} was not found in {sequence}") From 10aa214fcb2a05fd479e23a0d9c1d1ea617a7769 Mon Sep 17 00:00:00 2001 From: Hasenn Date: Mon, 14 Sep 2020 14:40:27 +0200 Subject: [PATCH 25/55] Docstrings and formatting improvements (#2418) * Fix spelling in docstrings * Improve comments and formatting * Update print statement to reflect doctest change * improve phrasing and apply black * Update rat_in_maze.py This method is recursive starting from (i, j) and going in one of four directions: up, down, left, right. If a path is found to destination it returns True otherwise it returns False. Co-authored-by: Christian Clauss --- backtracking/hamiltonian_cycle.py | 6 +++--- backtracking/rat_in_maze.py | 23 +++++++++++------------ boolean_algebra/quine_mc_cluskey.py | 2 +- cellular_automata/one_dimensional.py | 5 +++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/backtracking/hamiltonian_cycle.py b/backtracking/hamiltonian_cycle.py index 3bd61fc667d9..7be1ea350d7c 100644 --- a/backtracking/hamiltonian_cycle.py +++ b/backtracking/hamiltonian_cycle.py @@ -51,7 +51,7 @@ def util_hamilton_cycle(graph: List[List[int]], path: List[int], curr_ind: int) """ Pseudo-Code Base Case: - 1. Chceck if we visited all of vertices + 1. Check if we visited all of vertices 1.1 If last visited vertex has path to starting vertex return True either return False Recursive Step: @@ -59,8 +59,8 @@ def util_hamilton_cycle(graph: List[List[int]], path: List[int], curr_ind: int) Check if next vertex is valid for transiting from current vertex 2.1 Remember next vertex as next transition 2.2 Do recursive call and check if going to this vertex solves problem - 2.3 if next vertex leads to solution return True - 2.4 else backtrack, delete remembered vertex + 2.3 If next vertex leads to solution return True + 2.4 Else backtrack, delete remembered vertex Case 1: Use exact graph as in main function, with initialized values >>> graph = [[0, 1, 0, 1, 0], diff --git a/backtracking/rat_in_maze.py b/backtracking/rat_in_maze.py index ba96d6a52214..788aeac13c09 100644 --- a/backtracking/rat_in_maze.py +++ b/backtracking/rat_in_maze.py @@ -1,13 +1,13 @@ def solve_maze(maze: list) -> bool: """ - This method solves rat in maze algorithm. - In this problem we have n by n matrix and we have start point and end point - we want to go from source to distination. In this matrix 0 are block paths - 1 are open paths we can use. + This method solves the "rat in maze" problem. + In this problem we have some n by n matrix, a start point and an end point. + We want to go from the start to the end. In this matrix zeroes represent walls + and ones paths we can use. Parameters : maze(2D matrix) : maze Returns: - Return: True is maze has a solution or False if it does not. + Return: True if the maze has a solution or False if it does not. >>> maze = [[0, 1, 0, 1, 1], ... [0, 0, 0, 0, 0], ... [1, 0, 1, 0, 1], @@ -47,13 +47,13 @@ def solve_maze(maze: list) -> bool: ... [0, 1, 0], ... [1, 0, 0]] >>> solve_maze(maze) - Solution does not exists! + No solution exists! False >>> maze = [[0, 1], ... [1, 0]] >>> solve_maze(maze) - Solution does not exists! + No solution exists! False """ size = len(maze) @@ -63,16 +63,15 @@ def solve_maze(maze: list) -> bool: if solved: print("\n".join(str(row) for row in solutions)) else: - print("Solution does not exists!") + print("No solution exists!") return solved def run_maze(maze, i, j, solutions): """ - This method is recursive method which starts from i and j - and goes with 4 direction option up, down, left, right - if path found to destination it breaks and return True - otherwise False + This method is recursive starting from (i, j) and going in one of four directions: + up, down, left, right. + If a path is found to destination it returns True otherwise it returns False. Parameters: maze(2D matrix) : maze i, j : coordinates of matrix diff --git a/boolean_algebra/quine_mc_cluskey.py b/boolean_algebra/quine_mc_cluskey.py index 036cfbe63e79..a55b624483ca 100644 --- a/boolean_algebra/quine_mc_cluskey.py +++ b/boolean_algebra/quine_mc_cluskey.py @@ -146,7 +146,7 @@ def main(): minterms = [ int(x) for x in input( - "Enter the decimal representation of Minterms 'Spaces Seprated'\n" + "Enter the decimal representation of Minterms 'Spaces Separated'\n" ).split() ] binary = decimal_to_binary(no_of_variable, minterms) diff --git a/cellular_automata/one_dimensional.py b/cellular_automata/one_dimensional.py index 7819088c8cff..a6229dd9096f 100644 --- a/cellular_automata/one_dimensional.py +++ b/cellular_automata/one_dimensional.py @@ -32,8 +32,9 @@ def new_generation(cells: List[List[int]], rule: List[int], time: int) -> List[i next_generation = [] for i in range(population): # Get the neighbors of each cell - left_neighbor = 0 if i == 0 else cells[time][i - 1] # special: leftmost cell - right_neighbor = 0 if i == population - 1 else cells[time][i + 1] # rightmost + # Handle neighbours outside bounds by using 0 as their value + left_neighbor = 0 if i == 0 else cells[time][i - 1] + right_neighbor = 0 if i == population - 1 else cells[time][i + 1] # Define a new cell and add it to the new generation situation = 7 - int(f"{left_neighbor}{cells[time][i]}{right_neighbor}", 2) next_generation.append(rule[situation]) From cbbc43ba3ae24ad589d94beb65116c07917339ac Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Tue, 15 Sep 2020 04:33:08 +0800 Subject: [PATCH 26/55] Updated problem_04 in project_euler (#2427) * Updated problem_04 in project_euler * fixup! Format Python code with psf/black push * That number is larger than our acceptable range. * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Christian Clauss --- DIRECTORY.md | 6 ++++++ project_euler/problem_04/sol1.py | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index ac10afdc0ccd..1dceb887940c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -85,10 +85,12 @@ * [Harriscorner](https://github.com/TheAlgorithms/Python/blob/master/computer_vision/harriscorner.py) ## Conversions + * [Binary To Decimal](https://github.com/TheAlgorithms/Python/blob/master/conversions/binary_to_decimal.py) * [Decimal To Any](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_any.py) * [Decimal To Binary](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_binary.py) * [Decimal To Hexadecimal](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_hexadecimal.py) * [Decimal To Octal](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_octal.py) + * [Hexadecimal To Decimal](https://github.com/TheAlgorithms/Python/blob/master/conversions/hexadecimal_to_decimal.py) * [Prefix Conversions](https://github.com/TheAlgorithms/Python/blob/master/conversions/prefix_conversions.py) * [Roman To Integer](https://github.com/TheAlgorithms/Python/blob/master/conversions/roman_to_integer.py) * [Temperature Conversions](https://github.com/TheAlgorithms/Python/blob/master/conversions/temperature_conversions.py) @@ -222,6 +224,8 @@ ## File Transfer * [Receive File](https://github.com/TheAlgorithms/Python/blob/master/file_transfer/receive_file.py) * [Send File](https://github.com/TheAlgorithms/Python/blob/master/file_transfer/send_file.py) + * Tests + * [Test Send File](https://github.com/TheAlgorithms/Python/blob/master/file_transfer/tests/test_send_file.py) ## Fuzzy Logic * [Fuzzy Operations](https://github.com/TheAlgorithms/Python/blob/master/fuzzy_logic/fuzzy_operations.py) @@ -725,6 +729,7 @@ * [Binary Tree Traversals](https://github.com/TheAlgorithms/Python/blob/master/traversals/binary_tree_traversals.py) ## Web Programming + * [Covid Stats Via Xpath](https://github.com/TheAlgorithms/Python/blob/master/web_programming/covid_stats_via_xpath.py) * [Crawl Google Results](https://github.com/TheAlgorithms/Python/blob/master/web_programming/crawl_google_results.py) * [Current Stock Price](https://github.com/TheAlgorithms/Python/blob/master/web_programming/current_stock_price.py) * [Current Weather](https://github.com/TheAlgorithms/Python/blob/master/web_programming/current_weather.py) @@ -735,5 +740,6 @@ * [Fetch Jobs](https://github.com/TheAlgorithms/Python/blob/master/web_programming/fetch_jobs.py) * [Get Imdb Top 250 Movies Csv](https://github.com/TheAlgorithms/Python/blob/master/web_programming/get_imdb_top_250_movies_csv.py) * [Get Imdbtop](https://github.com/TheAlgorithms/Python/blob/master/web_programming/get_imdbtop.py) + * [Recaptcha Verification](https://github.com/TheAlgorithms/Python/blob/master/web_programming/recaptcha_verification.py) * [Slack Message](https://github.com/TheAlgorithms/Python/blob/master/web_programming/slack_message.py) * [World Covid19 Stats](https://github.com/TheAlgorithms/Python/blob/master/web_programming/world_covid19_stats.py) diff --git a/project_euler/problem_04/sol1.py b/project_euler/problem_04/sol1.py index 599345b5ab79..227b594d0df7 100644 --- a/project_euler/problem_04/sol1.py +++ b/project_euler/problem_04/sol1.py @@ -18,25 +18,34 @@ def solution(n): 29992 >>> solution(40000) 39893 + >>> solution(10000) + Traceback (most recent call last): + ... + ValueError: That number is larger than our acceptable range. """ # fetches the next number - for number in range(n - 1, 10000, -1): + for number in range(n - 1, 9999, -1): # converts number into string. - strNumber = str(number) + str_number = str(number) - # checks whether 'strNumber' is a palindrome. - if strNumber == strNumber[::-1]: + # checks whether 'str_number' is a palindrome. + if str_number == str_number[::-1]: divisor = 999 # if 'number' is a product of two 3-digit numbers # then number is the answer otherwise fetch next number. while divisor != 99: - if (number % divisor == 0) and (len(str(int(number / divisor))) == 3): + if (number % divisor == 0) and (len(str(number // divisor)) == 3.0): return number divisor -= 1 + raise ValueError("That number is larger than our acceptable range.") if __name__ == "__main__": + import doctest + + doctest.testmod() + print(solution(int(input().strip()))) From 1ac75f4683c8920382d9cbd676d7a3ae5fefc2a1 Mon Sep 17 00:00:00 2001 From: Ashley Jeji George <40469421+Ashley-J-George@users.noreply.github.com> Date: Wed, 16 Sep 2020 22:12:53 +0530 Subject: [PATCH 27/55] Create priority_queue_using_list.py (#2435) * Create priority_queue_using_list.py * Update priority_queue_using_list.py * Update priority_queue_using_list.py * Update priority_queue_using_list.py * Maximum queue size is 100 Co-authored-by: Christian Clauss --- .../queue/priority_queue_using_list.py | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 data_structures/queue/priority_queue_using_list.py diff --git a/data_structures/queue/priority_queue_using_list.py b/data_structures/queue/priority_queue_using_list.py new file mode 100644 index 000000000000..0ba4e88cd876 --- /dev/null +++ b/data_structures/queue/priority_queue_using_list.py @@ -0,0 +1,232 @@ +""" +Pure Python implementations of a Fixed Priority Queue and an Element Priority Queue +using Python lists. +""" + + +class OverFlowError(Exception): + pass + + +class UnderFlowError(Exception): + pass + + +class FixedPriorityQueue: + """ + Tasks can be added to a Priority Queue at any time and in any order but when Tasks + are removed then the Task with the highest priority is removed in FIFO order. In + code we will use three levels of priority with priority zero Tasks being the most + urgent (high priority) and priority 2 tasks being the least urgent. + + Examples + >>> fpq = FixedPriorityQueue() + >>> fpq.enqueue(0, 10) + >>> fpq.enqueue(1, 70) + >>> fpq.enqueue(0, 100) + >>> fpq.enqueue(2, 1) + >>> fpq.enqueue(2, 5) + >>> fpq.enqueue(1, 7) + >>> fpq.enqueue(2, 4) + >>> fpq.enqueue(1, 64) + >>> fpq.enqueue(0, 128) + >>> print(fpq) + Priority 0: [10, 100, 128] + Priority 1: [70, 7, 64] + Priority 2: [1, 5, 4] + >>> fpq.dequeue() + 10 + >>> fpq.dequeue() + 100 + >>> fpq.dequeue() + 128 + >>> fpq.dequeue() + 70 + >>> fpq.dequeue() + 7 + >>> print(fpq) + Priority 0: [] + Priority 1: [64] + Priority 2: [1, 5, 4] + >>> fpq.dequeue() + 64 + >>> fpq.dequeue() + 1 + >>> fpq.dequeue() + 5 + >>> fpq.dequeue() + 4 + >>> fpq.dequeue() + Traceback (most recent call last): + ... + priority_queue_using_list.UnderFlowError: All queues are empty + >>> print(fpq) + Priority 0: [] + Priority 1: [] + Priority 2: [] + """ + + def __init__(self): + self.queues = [ + [], + [], + [], + ] + + def enqueue(self, priority: int, data: int) -> None: + """ + Add an element to a queue based on its priority. + If the priority is invalid ValueError is raised. + If the queue is full an OverFlowError is raised. + """ + try: + if len(self.queues[priority]) >= 100: + raise OverflowError("Maximum queue size is 100") + self.queues[priority].append(data) + except IndexError: + raise ValueError("Valid priorities are 0, 1, and 2") + + def dequeue(self) -> int: + """ + Return the highest priority element in FIFO order. + If the queue is empty then an under flow exception is raised. + """ + for queue in self.queues: + if queue: + return queue.pop(0) + raise UnderFlowError("All queues are empty") + + def __str__(self) -> str: + return "\n".join(f"Priority {i}: {q}" for i, q in enumerate(self.queues)) + + +class ElementPriorityQueue: + """ + Element Priority Queue is the same as Fixed Priority Queue except that the value of + the element itself is the priority. The rules for priorities are the same the as + Fixed Priority Queue. + + >>> epq = ElementPriorityQueue() + >>> epq.enqueue(10) + >>> epq.enqueue(70) + >>> epq.enqueue(4) + >>> epq.enqueue(1) + >>> epq.enqueue(5) + >>> epq.enqueue(7) + >>> epq.enqueue(4) + >>> epq.enqueue(64) + >>> epq.enqueue(128) + >>> print(epq) + [10, 70, 4, 1, 5, 7, 4, 64, 128] + >>> epq.dequeue() + 1 + >>> epq.dequeue() + 4 + >>> epq.dequeue() + 4 + >>> epq.dequeue() + 5 + >>> epq.dequeue() + 7 + >>> epq.dequeue() + 10 + >>> print(epq) + [70, 64, 128] + >>> epq.dequeue() + 64 + >>> epq.dequeue() + 70 + >>> epq.dequeue() + 128 + >>> epq.dequeue() + Traceback (most recent call last): + ... + priority_queue_using_list.UnderFlowError: The queue is empty + >>> print(epq) + [] + """ + + def __init__(self): + self.queue = [] + + def enqueue(self, data: int) -> None: + """ + This function enters the element into the queue + If the queue is full an Exception is raised saying Over Flow! + """ + if len(self.queue) == 100: + raise OverFlowError("Maximum queue size is 100") + self.queue.append(data) + + def dequeue(self) -> int: + """ + Return the highest priority element in FIFO order. + If the queue is empty then an under flow exception is raised. + """ + if not self.queue: + raise UnderFlowError("The queue is empty") + else: + data = min(self.queue) + self.queue.remove(data) + return data + + def __str__(self) -> str: + """ + Prints all the elements within the Element Priority Queue + """ + return str(self.queue) + + +def fixed_priority_queue(): + fpq = FixedPriorityQueue() + fpq.enqueue(0, 10) + fpq.enqueue(1, 70) + fpq.enqueue(0, 100) + fpq.enqueue(2, 1) + fpq.enqueue(2, 5) + fpq.enqueue(1, 7) + fpq.enqueue(2, 4) + fpq.enqueue(1, 64) + fpq.enqueue(0, 128) + print(fpq) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq.dequeue()) + print(fpq.dequeue()) + + +def element_priority_queue(): + epq = ElementPriorityQueue() + epq.enqueue(10) + epq.enqueue(70) + epq.enqueue(100) + epq.enqueue(1) + epq.enqueue(5) + epq.enqueue(7) + epq.enqueue(4) + epq.enqueue(64) + epq.enqueue(128) + print(epq) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq.dequeue()) + print(epq.dequeue()) + + +if __name__ == "__main__": + fixed_priority_queue() + element_priority_queue() From 86fb2991d5f722a94c77df44b3a2de4cb0cbd4d7 Mon Sep 17 00:00:00 2001 From: poloso Date: Thu, 17 Sep 2020 02:41:10 -0500 Subject: [PATCH 28/55] Corrected filename and include static types (#2440) * Corrected name and include static types - The name of the file is now compliant with python naming conventions - Add static type as stated in contributing guidelines * Apply suggestions from code review - Delete documentation line to run doctests - Delete type hints for variables that comes from functions Co-authored-by: Christian Clauss * Add edge cases tests. * print(f"{target} was {not_str}found in {sequence}") Co-authored-by: Christian Clauss --- searches/simple-binary-search.py | 26 ---------------- searches/simple_binary_search.py | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 26 deletions(-) delete mode 100644 searches/simple-binary-search.py create mode 100644 searches/simple_binary_search.py diff --git a/searches/simple-binary-search.py b/searches/simple-binary-search.py deleted file mode 100644 index 80e43ea346b2..000000000000 --- a/searches/simple-binary-search.py +++ /dev/null @@ -1,26 +0,0 @@ -# A binary search implementation to test if a number is in a list of elements - - -def binary_search(a_list, item): - """ - >>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42] - >>> print(binary_search(test_list, 3)) - False - >>> print(binary_search(test_list, 13)) - True - """ - if len(a_list) == 0: - return False - midpoint = len(a_list) // 2 - if a_list[midpoint] == item: - return True - if item < a_list[midpoint]: - return binary_search(a_list[:midpoint], item) - else: - return binary_search(a_list[midpoint + 1 :], item) - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/searches/simple_binary_search.py b/searches/simple_binary_search.py new file mode 100644 index 000000000000..1d898e2d9ee0 --- /dev/null +++ b/searches/simple_binary_search.py @@ -0,0 +1,53 @@ +""" +Pure Python implementation of a binary search algorithm. + +For doctests run following command: +python3 -m doctest -v simple_binary_search.py + +For manual testing run: +python3 simple_binary_search.py +""" +from typing import List + + +def binary_search(a_list: List[int], item: int) -> bool: + """ + >>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42] + >>> print(binary_search(test_list, 3)) + False + >>> print(binary_search(test_list, 13)) + True + >>> print(binary_search([4, 4, 5, 6, 7], 4)) + True + >>> print(binary_search([4, 4, 5, 6, 7], -10)) + False + >>> print(binary_search([-18, 2], -18)) + True + >>> print(binary_search([5], 5)) + True + >>> print(binary_search(['a', 'c', 'd'], 'c')) + True + >>> print(binary_search(['a', 'c', 'd'], 'f')) + False + >>> print(binary_search([], 1)) + False + >>> print(binary_search([.1, .4 , -.1], .1)) + True + """ + if len(a_list) == 0: + return False + midpoint = len(a_list) // 2 + if a_list[midpoint] == item: + return True + if item < a_list[midpoint]: + return binary_search(a_list[:midpoint], item) + else: + return binary_search(a_list[midpoint + 1:], item) + + +if __name__ == "__main__": + user_input = input("Enter numbers separated by comma:\n").strip() + sequence = [int(item.strip()) for item in user_input.split(",")] + target = int(input("Enter the number to be found in the list:\n").strip()) + not_str = "" if binary_search(sequence, target) else "not " + print(f"{target} was {not_str}found in {sequence}") From 2de2267319c2c44e416b840daa370ef463d655fe Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Thu, 17 Sep 2020 17:37:53 +0800 Subject: [PATCH 29/55] Updated problem_06 in Project Euler (#2439) * * rename variable * fix type hint * fix doctest * added test function * fixed import error * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- project_euler/problem_06/sol1.py | 16 +++++++++------- project_euler/problem_06/sol2.py | 12 +++++++----- project_euler/problem_06/sol3.py | 5 ++++- project_euler/problem_06/sol4.py | 5 ++++- project_euler/problem_06/test_solutions.py | 18 ++++++++++++++++++ 5 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 project_euler/problem_06/test_solutions.py diff --git a/project_euler/problem_06/sol1.py b/project_euler/problem_06/sol1.py index 513b354679a9..d6506ea2839c 100644 --- a/project_euler/problem_06/sol1.py +++ b/project_euler/problem_06/sol1.py @@ -15,7 +15,7 @@ """ -def solution(n): +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -28,14 +28,16 @@ def solution(n): >>> solution(50) 1582700 """ - suma = 0 - sumb = 0 + sum_of_squares = 0 + sum_of_ints = 0 for i in range(1, n + 1): - suma += i ** 2 - sumb += i - sum = sumb ** 2 - suma - return sum + sum_of_squares += i ** 2 + sum_of_ints += i + return sum_of_ints ** 2 - sum_of_squares if __name__ == "__main__": + import doctest + + doctest.testmod() print(solution(int(input().strip()))) diff --git a/project_euler/problem_06/sol2.py b/project_euler/problem_06/sol2.py index 18cdb51752ea..5032775f9f77 100644 --- a/project_euler/problem_06/sol2.py +++ b/project_euler/problem_06/sol2.py @@ -15,7 +15,7 @@ """ -def solution(n): +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -28,11 +28,13 @@ def solution(n): >>> solution(50) 1582700 """ - suma = n * (n + 1) / 2 - suma **= 2 - sumb = n * (n + 1) * (2 * n + 1) / 6 - return int(suma - sumb) + sum_cubes = (n * (n + 1) // 2) ** 2 + sum_squares = n * (n + 1) * (2 * n + 1) // 6 + return sum_cubes - sum_squares if __name__ == "__main__": + import doctest + + doctest.testmod() print(solution(int(input().strip()))) diff --git a/project_euler/problem_06/sol3.py b/project_euler/problem_06/sol3.py index ee739c9a1293..385ad05151fb 100644 --- a/project_euler/problem_06/sol3.py +++ b/project_euler/problem_06/sol3.py @@ -16,7 +16,7 @@ import math -def solution(n): +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -35,4 +35,7 @@ def solution(n): if __name__ == "__main__": + import doctest + + doctest.testmod() print(solution(int(input().strip()))) diff --git a/project_euler/problem_06/sol4.py b/project_euler/problem_06/sol4.py index 07eed57ba9b5..912a3e8f6096 100644 --- a/project_euler/problem_06/sol4.py +++ b/project_euler/problem_06/sol4.py @@ -15,7 +15,7 @@ """ -def solution(n): +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -36,4 +36,7 @@ def solution(n): if __name__ == "__main__": + import doctest + + doctest.testmod() print(solution(int(input("Enter a number: ").strip()))) diff --git a/project_euler/problem_06/test_solutions.py b/project_euler/problem_06/test_solutions.py new file mode 100644 index 000000000000..6d5337789655 --- /dev/null +++ b/project_euler/problem_06/test_solutions.py @@ -0,0 +1,18 @@ +from .sol1 import solution as sol1 +from .sol2 import solution as sol2 +from .sol3 import solution as sol3 +from .sol4 import solution as sol4 + + +def test_solutions() -> None: + """ + >>> test_solutions() + """ + assert sol1(10) == sol2(10) == sol3(10) == sol4(10) == 2640 + assert sol1(15) == sol2(15) == sol3(15) == sol4(15) == 13160 + assert sol1(20) == sol2(20) == sol3(20) == sol4(20) == 41230 + assert sol1(50) == sol2(50) == sol3(50) == sol4(50) == 1582700 + + +if __name__ == "__main__": + test_solutions() From 0dea049f4462444c4d44a7c66b092cef1245a646 Mon Sep 17 00:00:00 2001 From: avych <7556744+avych@users.noreply.github.com> Date: Fri, 18 Sep 2020 12:07:49 +0530 Subject: [PATCH 30/55] Added static type checking to polynom-for-points.py towards issue #2128 (#2335) * Added static type checking to linear_algebra/src/polynom-for-points.py * Fixed TravisCI errors * Update polynom-for-points.py Co-authored-by: Christian Clauss --- linear_algebra/src/polynom-for-points.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/linear_algebra/src/polynom-for-points.py b/linear_algebra/src/polynom-for-points.py index dc0c3d95102e..8db89fc2c1ea 100644 --- a/linear_algebra/src/polynom-for-points.py +++ b/linear_algebra/src/polynom-for-points.py @@ -1,4 +1,7 @@ -def points_to_polynomial(coordinates): +from typing import List + + +def points_to_polynomial(coordinates: List[List[int]]) -> str: """ coordinates is a two dimensional matrix: [[x, y], [x, y], ...] number of points you want to use @@ -57,7 +60,7 @@ def points_to_polynomial(coordinates): while count_of_line < x: count_in_line = 0 a = coordinates[count_of_line][0] - count_line = [] + count_line: List[int] = [] while count_in_line < x: count_line.append(a ** (x - (count_in_line + 1))) count_in_line += 1 @@ -66,7 +69,7 @@ def points_to_polynomial(coordinates): count_of_line = 0 # put the y values into a vector - vector = [] + vector: List[int] = [] while count_of_line < x: vector.append(coordinates[count_of_line][1]) count_of_line += 1 @@ -80,7 +83,7 @@ def points_to_polynomial(coordinates): zahlen += 1 if zahlen == x: break - bruch = (matrix[zahlen][count]) / (matrix[count][count]) + bruch = matrix[zahlen][count] / matrix[count][count] for counting_columns, item in enumerate(matrix[count]): # manipulating all the values in the matrix matrix[zahlen][counting_columns] -= item * bruch @@ -91,7 +94,7 @@ def points_to_polynomial(coordinates): count = 0 # make solutions - solution = [] + solution: List[str] = [] while count < x: solution.append(vector[count] / matrix[count][count]) count += 1 @@ -100,7 +103,7 @@ def points_to_polynomial(coordinates): solved = "f(x)=" while count < x: - remove_e = str(solution[count]).split("E") + remove_e: List[str] = str(solution[count]).split("E") if len(remove_e) > 1: solution[count] = remove_e[0] + "*10^" + remove_e[1] solved += "x^" + str(x - (count + 1)) + "*" + str(solution[count]) From dc415ec14a7918a8dce0af6ab34f6dc88c55852e Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Fri, 18 Sep 2020 15:55:02 +0800 Subject: [PATCH 31/55] Added double linear search recursion (#2445) * double linear search recursion * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- searches/double_linear_search_recursion.py | 35 ++++++++++++++++++++++ searches/simple_binary_search.py | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 searches/double_linear_search_recursion.py diff --git a/searches/double_linear_search_recursion.py b/searches/double_linear_search_recursion.py new file mode 100644 index 000000000000..1c483e974ca7 --- /dev/null +++ b/searches/double_linear_search_recursion.py @@ -0,0 +1,35 @@ +def search(list_data: list, key: int, left: int = 0, right: int = 0) -> int: + """ + Iterate through the array to find the index of key using recursion. + :param list_data: the list to be searched + :param key: the key to be searched + :param left: the index of first element + :param right: the index of last element + :return: the index of key value if found, -1 otherwise. + + >>> search(list(range(0, 11)), 5) + 5 + >>> search([1, 2, 4, 5, 3], 4) + 2 + >>> search([1, 2, 4, 5, 3], 6) + -1 + >>> search([5], 5) + 0 + >>> search([], 1) + -1 + """ + right = right or len(list_data) - 1 + if left > right: + return -1 + elif list_data[left] == key: + return left + elif list_data[right] == key: + return right + else: + return search(list_data, key, left + 1, right - 1) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/searches/simple_binary_search.py b/searches/simple_binary_search.py index 1d898e2d9ee0..b6215312fb2d 100644 --- a/searches/simple_binary_search.py +++ b/searches/simple_binary_search.py @@ -42,7 +42,7 @@ def binary_search(a_list: List[int], item: int) -> bool: if item < a_list[midpoint]: return binary_search(a_list[:midpoint], item) else: - return binary_search(a_list[midpoint + 1:], item) + return binary_search(a_list[midpoint + 1 :], item) if __name__ == "__main__": From ecac7b097371b3f87bfd40b0d7d01d933f38b726 Mon Sep 17 00:00:00 2001 From: kanthuc Date: Fri, 18 Sep 2020 13:53:50 -0700 Subject: [PATCH 32/55] Contains loops.py add (#2442) * added an algorithm which checks a linked list for loops and returns true if one is found * added doctests and clarified meaning of loop * Define Node.__iter__() * Update and rename has_loop.py to has_duplicate_data.py * Update has_duplicate_data.py * Update has_duplicate_data.py * Update and rename has_duplicate_data.py to has_loop.py * Update has_loop.py Co-authored-by: Christian Clauss --- data_structures/linked_list/has_loop.py | 60 +++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 data_structures/linked_list/has_loop.py diff --git a/data_structures/linked_list/has_loop.py b/data_structures/linked_list/has_loop.py new file mode 100644 index 000000000000..405ece7e27c8 --- /dev/null +++ b/data_structures/linked_list/has_loop.py @@ -0,0 +1,60 @@ +from typing import Any + + +class ContainsLoopError(Exception): + pass + + +class Node: + def __init__(self, data: Any) -> None: + self.data = data + self.next_node = None + + def __iter__(self): + node = self + visited = [] + while node: + if node in visited: + raise ContainsLoopError + visited.append(node) + yield node.data + node = node.next_node + + @property + def has_loop(self) -> bool: + """ + A loop is when the exact same Node appears more than once in a linked list. + >>> root_node = Node(1) + >>> root_node.next_node = Node(2) + >>> root_node.next_node.next_node = Node(3) + >>> root_node.next_node.next_node.next_node = Node(4) + >>> root_node.has_loop + False + >>> root_node.next_node.next_node.next_node = root_node.next_node + >>> root_node.has_loop + True + """ + try: + list(self) + return False + except ContainsLoopError: + return True + + +if __name__ == "__main__": + root_node = Node(1) + root_node.next_node = Node(2) + root_node.next_node.next_node = Node(3) + root_node.next_node.next_node.next_node = Node(4) + print(root_node.has_loop) # False + root_node.next_node.next_node.next_node = root_node.next_node + print(root_node.has_loop) # True + + root_node = Node(5) + root_node.next_node = Node(6) + root_node.next_node.next_node = Node(5) + root_node.next_node.next_node.next_node = Node(6) + print(root_node.has_loop) # False + + root_node = Node(1) + print(root_node.has_loop) # False From 363858ef3baf4e1a34822d8dd0945de3e3e384cf Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 19 Sep 2020 07:13:10 +0200 Subject: [PATCH 33/55] hyphen_files = [file for file in filepaths if "-" in file] (#2447) * hyphen_files = [file for file in filepaths if "-" in file] * updating DIRECTORY.md * Rename recursive-quick-sort.py to recursive_quick_sort.py * updating DIRECTORY.md * Rename aho-corasick.py to aho_corasick.py * updating DIRECTORY.md * Rename polynom-for-points.py to polynom_for_points.py * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 12 ++++++++---- .../{polynom-for-points.py => polynom_for_points.py} | 0 scripts/validate_filenames.py | 7 ++++++- ...cursive-quick-sort.py => recursive_quick_sort.py} | 0 strings/{aho-corasick.py => aho_corasick.py} | 0 5 files changed, 14 insertions(+), 5 deletions(-) rename linear_algebra/src/{polynom-for-points.py => polynom_for_points.py} (100%) rename sorts/{recursive-quick-sort.py => recursive_quick_sort.py} (100%) rename strings/{aho-corasick.py => aho_corasick.py} (100%) diff --git a/DIRECTORY.md b/DIRECTORY.md index 1dceb887940c..3c066122a167 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -131,6 +131,7 @@ * [Deque Doubly](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/deque_doubly.py) * [Doubly Linked List](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/doubly_linked_list.py) * [From Sequence](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/from_sequence.py) + * [Has Loop](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/has_loop.py) * [Is Palindrome](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/is_palindrome.py) * [Middle Element Of Linked List](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/middle_element_of_linked_list.py) * [Print Reverse](https://github.com/TheAlgorithms/Python/blob/master/data_structures/linked_list/print_reverse.py) @@ -141,6 +142,7 @@ * [Circular Queue](https://github.com/TheAlgorithms/Python/blob/master/data_structures/queue/circular_queue.py) * [Double Ended Queue](https://github.com/TheAlgorithms/Python/blob/master/data_structures/queue/double_ended_queue.py) * [Linked Queue](https://github.com/TheAlgorithms/Python/blob/master/data_structures/queue/linked_queue.py) + * [Priority Queue Using List](https://github.com/TheAlgorithms/Python/blob/master/data_structures/queue/priority_queue_using_list.py) * [Queue On List](https://github.com/TheAlgorithms/Python/blob/master/data_structures/queue/queue_on_list.py) * [Queue On Pseudo Stack](https://github.com/TheAlgorithms/Python/blob/master/data_structures/queue/queue_on_pseudo_stack.py) * Stacks @@ -303,7 +305,7 @@ ## Linear Algebra * Src * [Lib](https://github.com/TheAlgorithms/Python/blob/master/linear_algebra/src/lib.py) - * [Polynom-For-Points](https://github.com/TheAlgorithms/Python/blob/master/linear_algebra/src/polynom-for-points.py) + * [Polynom For Points](https://github.com/TheAlgorithms/Python/blob/master/linear_algebra/src/polynom_for_points.py) * [Power Iteration](https://github.com/TheAlgorithms/Python/blob/master/linear_algebra/src/power_iteration.py) * [Rayleigh Quotient](https://github.com/TheAlgorithms/Python/blob/master/linear_algebra/src/rayleigh_quotient.py) * [Test Linear Algebra](https://github.com/TheAlgorithms/Python/blob/master/linear_algebra/src/test_linear_algebra.py) @@ -518,6 +520,7 @@ * [Sol2](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_06/sol2.py) * [Sol3](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_06/sol3.py) * [Sol4](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_06/sol4.py) + * [Test Solutions](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_06/test_solutions.py) * Problem 07 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_07/sol1.py) * [Sol2](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_07/sol2.py) @@ -648,6 +651,7 @@ ## Searches * [Binary Search](https://github.com/TheAlgorithms/Python/blob/master/searches/binary_search.py) * [Double Linear Search](https://github.com/TheAlgorithms/Python/blob/master/searches/double_linear_search.py) + * [Double Linear Search Recursion](https://github.com/TheAlgorithms/Python/blob/master/searches/double_linear_search_recursion.py) * [Fibonacci Search](https://github.com/TheAlgorithms/Python/blob/master/searches/fibonacci_search.py) * [Hill Climbing](https://github.com/TheAlgorithms/Python/blob/master/searches/hill_climbing.py) * [Interpolation Search](https://github.com/TheAlgorithms/Python/blob/master/searches/interpolation_search.py) @@ -655,7 +659,7 @@ * [Linear Search](https://github.com/TheAlgorithms/Python/blob/master/searches/linear_search.py) * [Quick Select](https://github.com/TheAlgorithms/Python/blob/master/searches/quick_select.py) * [Sentinel Linear Search](https://github.com/TheAlgorithms/Python/blob/master/searches/sentinel_linear_search.py) - * [Simple-Binary-Search](https://github.com/TheAlgorithms/Python/blob/master/searches/simple-binary-search.py) + * [Simple Binary Search](https://github.com/TheAlgorithms/Python/blob/master/searches/simple_binary_search.py) * [Simulated Annealing](https://github.com/TheAlgorithms/Python/blob/master/searches/simulated_annealing.py) * [Tabu Search](https://github.com/TheAlgorithms/Python/blob/master/searches/tabu_search.py) * [Ternary Search](https://github.com/TheAlgorithms/Python/blob/master/searches/ternary_search.py) @@ -689,9 +693,9 @@ * [Radix Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/radix_sort.py) * [Random Normal Distribution Quicksort](https://github.com/TheAlgorithms/Python/blob/master/sorts/random_normal_distribution_quicksort.py) * [Random Pivot Quick Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/random_pivot_quick_sort.py) - * [Recursive-Quick-Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/recursive-quick-sort.py) * [Recursive Bubble Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/recursive_bubble_sort.py) * [Recursive Insertion Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/recursive_insertion_sort.py) + * [Recursive Quick Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/recursive_quick_sort.py) * [Selection Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/selection_sort.py) * [Shell Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/shell_sort.py) * [Stooge Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/stooge_sort.py) @@ -703,7 +707,7 @@ * [Wiggle Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/wiggle_sort.py) ## Strings - * [Aho-Corasick](https://github.com/TheAlgorithms/Python/blob/master/strings/aho-corasick.py) + * [Aho Corasick](https://github.com/TheAlgorithms/Python/blob/master/strings/aho_corasick.py) * [Boyer Moore Search](https://github.com/TheAlgorithms/Python/blob/master/strings/boyer_moore_search.py) * [Capitalize](https://github.com/TheAlgorithms/Python/blob/master/strings/capitalize.py) * [Check Anagrams](https://github.com/TheAlgorithms/Python/blob/master/strings/check_anagrams.py) diff --git a/linear_algebra/src/polynom-for-points.py b/linear_algebra/src/polynom_for_points.py similarity index 100% rename from linear_algebra/src/polynom-for-points.py rename to linear_algebra/src/polynom_for_points.py diff --git a/scripts/validate_filenames.py b/scripts/validate_filenames.py index 01712e8f7707..ca4e2c9fcd57 100755 --- a/scripts/validate_filenames.py +++ b/scripts/validate_filenames.py @@ -17,12 +17,17 @@ print(f"{len(space_files)} files contain space characters:") print("\n".join(space_files) + "\n") +hyphen_files = [file for file in filepaths if "-" in file] +if hyphen_files: + print(f"{len(hyphen_files)} files contain space characters:") + print("\n".join(hyphen_files) + "\n") + nodir_files = [file for file in filepaths if os.sep not in file] if nodir_files: print(f"{len(nodir_files)} files are not in a directory:") print("\n".join(nodir_files) + "\n") -bad_files = len(upper_files + space_files + nodir_files) +bad_files = len(upper_files + space_files + hyphen_files + nodir_files) if bad_files: import sys diff --git a/sorts/recursive-quick-sort.py b/sorts/recursive_quick_sort.py similarity index 100% rename from sorts/recursive-quick-sort.py rename to sorts/recursive_quick_sort.py diff --git a/strings/aho-corasick.py b/strings/aho_corasick.py similarity index 100% rename from strings/aho-corasick.py rename to strings/aho_corasick.py From 697495b017512268ff42d35c05fd4a69de57623e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 19 Sep 2020 07:25:18 +0200 Subject: [PATCH 34/55] Fix copy / paste oversight (#2448) --- scripts/validate_filenames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/validate_filenames.py b/scripts/validate_filenames.py index ca4e2c9fcd57..f09c1527cb0d 100755 --- a/scripts/validate_filenames.py +++ b/scripts/validate_filenames.py @@ -19,7 +19,7 @@ hyphen_files = [file for file in filepaths if "-" in file] if hyphen_files: - print(f"{len(hyphen_files)} files contain space characters:") + print(f"{len(hyphen_files)} files contain hyphen characters:") print("\n".join(hyphen_files) + "\n") nodir_files = [file for file in filepaths if os.sep not in file] From b22596cd965ef53b0faa4e2d32044a21c1458aab Mon Sep 17 00:00:00 2001 From: mohammadreza490 <47437328+mohammadreza490@users.noreply.github.com> Date: Sat, 19 Sep 2020 06:36:56 +0100 Subject: [PATCH 35/55] bin_to_octal (#2431) * bin_to_octal Converts binary values to the octal equivalent. * Update bin_to_octal * Update conversions/bin_to_octal Co-authored-by: Christian Clauss * Update conversions/bin_to_octal Co-authored-by: Du Yuanchao * Update conversions/bin_to_octal Co-authored-by: Du Yuanchao * Update conversions/bin_to_octal Co-authored-by: Du Yuanchao * Rename bin_to_octal to bin_to_octal.py Co-authored-by: Christian Clauss Co-authored-by: Du Yuanchao --- conversions/bin_to_octal.py | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 conversions/bin_to_octal.py diff --git a/conversions/bin_to_octal.py b/conversions/bin_to_octal.py new file mode 100644 index 000000000000..39aa4646e7a5 --- /dev/null +++ b/conversions/bin_to_octal.py @@ -0,0 +1,45 @@ +""" +The function below will convert any binary string to the octal equivalent. + +>>> bin_to_octal("1111") +'17' + +>>> bin_to_octal("101010101010011") +'52523' + +>>> bin_to_octal("") +Traceback (most recent call last): +... +ValueError: Empty string was passed to the function +>>> bin_to_octal("a-1") +Traceback (most recent call last): +... +ValueError: Non-binary value was passed to the function +""" + + +def bin_to_octal(bin_string: str) -> str: + if not all(char in "01" for char in bin_string): + raise ValueError("Non-binary value was passed to the function") + if not bin_string: + raise ValueError("Empty string was passed to the function") + oct_string = "" + while len(bin_string) % 3 != 0: + bin_string = "0" + bin_string + bin_string_in_3_list = [ + bin_string[index: index + 3] + for index, value in enumerate(bin_string) + if index % 3 == 0 + ] + for bin_group in bin_string_in_3_list: + oct_val = 0 + for index, val in enumerate(bin_group): + oct_val += int(2 ** (2 - index) * int(val)) + oct_string += str(oct_val) + return oct_string + + +if __name__ == "__main__": + from doctest import testmod + + testmod() From b05081a717546f021014454d03bcf2f6145148aa Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 19 Sep 2020 08:58:08 +0200 Subject: [PATCH 36/55] Update and rename bin_to_octal.py to binary_to_octal.py (#2449) * Update and rename bin_to_octal.py to binary_to_octal.py * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- conversions/{bin_to_octal.py => binary_to_octal.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename conversions/{bin_to_octal.py => binary_to_octal.py} (96%) diff --git a/conversions/bin_to_octal.py b/conversions/binary_to_octal.py similarity index 96% rename from conversions/bin_to_octal.py rename to conversions/binary_to_octal.py index 39aa4646e7a5..8b594887867e 100644 --- a/conversions/bin_to_octal.py +++ b/conversions/binary_to_octal.py @@ -27,7 +27,7 @@ def bin_to_octal(bin_string: str) -> str: while len(bin_string) % 3 != 0: bin_string = "0" + bin_string bin_string_in_3_list = [ - bin_string[index: index + 3] + bin_string[index : index + 3] for index, value in enumerate(bin_string) if index % 3 == 0 ] From 9b73884def8ea77e563764591a3eeb0fee1d7024 Mon Sep 17 00:00:00 2001 From: Susmith98 <33018940+susmith98@users.noreply.github.com> Date: Sun, 20 Sep 2020 01:19:37 +0530 Subject: [PATCH 37/55] Added a function that checks if given string can be rearranged to form a palindrome. (#2450) * Added check_if_string_can_be_rearranged_as_palindrome function. * Added counter implementation and benchmark function. * flake changes * Update and rename check_if_string_can_be_converted_to_palindrome.py to can_string_be_rearranged_as_palindrome.py * Update can_string_be_rearranged_as_palindrome.py * # Co-authored-by: svedire Co-authored-by: Christian Clauss --- .../can_string_be_rearranged_as_palindrome.py | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 strings/can_string_be_rearranged_as_palindrome.py diff --git a/strings/can_string_be_rearranged_as_palindrome.py b/strings/can_string_be_rearranged_as_palindrome.py new file mode 100644 index 000000000000..92bc3b95b243 --- /dev/null +++ b/strings/can_string_be_rearranged_as_palindrome.py @@ -0,0 +1,113 @@ +# Created by susmith98 + +from collections import Counter +from timeit import timeit + +# Problem Description: +# Check if characters of the given string can be rearranged to form a palindrome. +# Counter is faster for long strings and non-Counter is faster for short strings. + + +def can_string_be_rearranged_as_palindrome_counter(input_str: str = "",) -> bool: + """ + A Palindrome is a String that reads the same forward as it does backwards. + Examples of Palindromes mom, dad, malayalam + >>> can_string_be_rearranged_as_palindrome_counter("Momo") + True + >>> can_string_be_rearranged_as_palindrome_counter("Mother") + False + >>> can_string_be_rearranged_as_palindrome_counter("Father") + False + >>> can_string_be_rearranged_as_palindrome_counter("A man a plan a canal Panama") + True + """ + return sum(c % 2 for c in Counter(input_str.replace(" ", "").lower()).values()) < 2 + + +def can_string_be_rearranged_as_palindrome(input_str: str = "") -> bool: + """ + A Palindrome is a String that reads the same forward as it does backwards. + Examples of Palindromes mom, dad, malayalam + >>> can_string_be_rearranged_as_palindrome("Momo") + True + >>> can_string_be_rearranged_as_palindrome("Mother") + False + >>> can_string_be_rearranged_as_palindrome("Father") + False + >>> can_string_be_rearranged_as_palindrome_counter("A man a plan a canal Panama") + True + """ + if len(input_str) == 0: + return True + lower_case_input_str = input_str.replace(" ", "").lower() + # character_freq_dict: Stores the frequency of every character in the input string + character_freq_dict = {} + + for character in lower_case_input_str: + character_freq_dict[character] = character_freq_dict.get(character, 0) + 1 + """ + Above line of code is equivalent to: + 1) Getting the frequency of current character till previous index + >>> character_freq = character_freq_dict.get(character, 0) + 2) Incrementing the frequency of current character by 1 + >>> character_freq = character_freq + 1 + 3) Updating the frequency of current character + >>> character_freq_dict[character] = character_freq + """ + """ + OBSERVATIONS: + Even length palindrome + -> Every character appears even no.of times. + Odd length palindrome + -> Every character appears even no.of times except for one character. + LOGIC: + Step 1: We'll count number of characters that appear odd number of times i.e oddChar + Step 2:If we find more than 1 character that appears odd number of times, + It is not possible to rearrange as a palindrome + """ + oddChar = 0 + + for character_count in character_freq_dict.values(): + if character_count % 2: + oddChar += 1 + if oddChar > 1: + return False + return True + + +def benchmark(input_str: str = "") -> None: + """ + Benchmark code for comparing above 2 functions + """ + print("\nFor string = ", input_str, ":") + print( + "> can_string_be_rearranged_as_palindrome_counter()", + "\tans =", + can_string_be_rearranged_as_palindrome_counter(input_str), + "\ttime =", + timeit( + "z.can_string_be_rearranged_as_palindrome_counter(z.check_str)", + setup="import __main__ as z", + ), + "seconds", + ) + print( + "> can_string_be_rearranged_as_palindrome()", + "\tans =", + can_string_be_rearranged_as_palindrome(input_str), + "\ttime =", + timeit( + "z.can_string_be_rearranged_as_palindrome(z.check_str)", + setup="import __main__ as z", + ), + "seconds", + ) + + +if __name__ == "__main__": + check_str = input( + "Enter string to determine if it can be rearranged as a palindrome or not: " + ).strip() + benchmark(check_str) + status = can_string_be_rearranged_as_palindrome_counter(check_str) + print(f"{check_str} can {'' if status else 'not '}be rearranged as a palindrome") From ea0759dbaa99721173bbe1a3c45cddf5f8ad4109 Mon Sep 17 00:00:00 2001 From: Dhruv Date: Sun, 20 Sep 2020 17:22:13 +0530 Subject: [PATCH 38/55] Create problem_54 in project Euler (#2451) * Add solution and test files for project euler 54 * Update sol1.py * updating DIRECTORY.md * Fix: use proper path to open files * Commit suggestions: - Use list comprehension instead of map - Sort imports using isort * Changes made as suggested (simplified a lot): - List and set comprehension instead of itemgetter - Using enumerate as it's easy to read - Divided into list of card values and set of card suit as set will remove all the duplicate values. So, no need for double indexing. - Add test for testing multiple calls to five_high_straight function * Add suggestions and simplified: - Split generate_random_hands function into two: - First will generate a random hand - Second, which will be called, will return a generator object Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 4 + project_euler/problem_54/__init__.py | 0 project_euler/problem_54/poker_hands.txt | 1000 +++++++++++++++++++ project_euler/problem_54/sol1.py | 358 +++++++ project_euler/problem_54/test_poker_hand.py | 228 +++++ 5 files changed, 1590 insertions(+) create mode 100644 project_euler/problem_54/__init__.py create mode 100644 project_euler/problem_54/poker_hands.txt create mode 100644 project_euler/problem_54/sol1.py create mode 100644 project_euler/problem_54/test_poker_hand.py diff --git a/DIRECTORY.md b/DIRECTORY.md index 3c066122a167..d91d34803a1c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -86,6 +86,7 @@ ## Conversions * [Binary To Decimal](https://github.com/TheAlgorithms/Python/blob/master/conversions/binary_to_decimal.py) + * [Binary To Octal](https://github.com/TheAlgorithms/Python/blob/master/conversions/binary_to_octal.py) * [Decimal To Any](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_any.py) * [Decimal To Binary](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_binary.py) * [Decimal To Hexadecimal](https://github.com/TheAlgorithms/Python/blob/master/conversions/decimal_to_hexadecimal.py) @@ -628,6 +629,9 @@ * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_52/sol1.py) * Problem 53 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_53/sol1.py) + * Problem 54 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_54/sol1.py) + * [Test Poker Hand](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_54/test_poker_hand.py) * Problem 55 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_55/sol1.py) * Problem 551 diff --git a/project_euler/problem_54/__init__.py b/project_euler/problem_54/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/project_euler/problem_54/poker_hands.txt b/project_euler/problem_54/poker_hands.txt new file mode 100644 index 000000000000..9ab00248c061 --- /dev/null +++ b/project_euler/problem_54/poker_hands.txt @@ -0,0 +1,1000 @@ +8C TS KC 9H 4S 7D 2S 5D 3S AC +5C AD 5D AC 9C 7C 5H 8D TD KS +3H 7H 6S KC JS QH TD JC 2D 8S +TH 8H 5C QS TC 9H 4D JC KS JS +7C 5H KC QH JD AS KH 4C AD 4S +5H KS 9C 7D 9H 8D 3S 5D 5C AH +6H 4H 5C 3H 2H 3S QH 5S 6S AS +TD 8C 4H 7C TC KC 4C 3H 7S KS +7C 9C 6D KD 3H 4C QS QC AC KH +JC 6S 5H 2H 2D KD 9D 7C AS JS +AD QH TH 9D 8H TS 6D 3S AS AC +2H 4S 5C 5S TC KC JD 6C TS 3C +QD AS 6H JS 2C 3D 9H KC 4H 8S +KD 8S 9S 7C 2S 3S 6D 6S 4H KC +3C 8C 2D 7D 4D 9S 4S QH 4H JD +8C KC 7S TC 2D TS 8H QD AC 5C +3D KH QD 6C 6S AD AS 8H 2H QS +6S 8D 4C 8S 6C QH TC 6D 7D 9D +2S 8D 8C 4C TS 9S 9D 9C AC 3D +3C QS 2S 4H JH 3D 2D TD 8S 9H +5H QS 8S 6D 3C 8C JD AS 7H 7D +6H TD 9D AS JH 6C QC 9S KD JC +AH 8S QS 4D TH AC TS 3C 3D 5C +5S 4D JS 3D 8H 6C TS 3S AD 8C +6D 7C 5D 5H 3S 5C JC 2H 5S 3D +5H 6H 2S KS 3D 5D JD 7H JS 8H +KH 4H AS JS QS QC TC 6D 7C KS +3D QS TS 2H JS 4D AS 9S JC KD +QD 5H 4D 5D KH 7H 3D JS KD 4H +2C 9H 6H 5C 9D 6C JC 2D TH 9S +7D 6D AS QD JH 4D JS 7C QS 5C +3H KH QD AD 8C 8H 3S TH 9D 5S +AH 9S 4D 9D 8S 4H JS 3C TC 8D +2C KS 5H QD 3S TS 9H AH AD 8S +5C 7H 5D KD 9H 4D 3D 2D KS AD +KS KC 9S 6D 2C QH 9D 9H TS TC +9C 6H 5D QH 4D AD 6D QC JS KH +9S 3H 9D JD 5C 4D 9H AS TC QH +2C 6D JC 9C 3C AD 9S KH 9D 7D +KC 9C 7C JC JS KD 3H AS 3C 7D +QD KH QS 2C 3S 8S 8H 9H 9C JC +QH 8D 3C KC 4C 4H 6D AD 9H 9D +3S KS QS 7H KH 7D 5H 5D JD AD +2H 2C 6H TH TC 7D 8D 4H 8C AS +4S 2H AC QC 3S 6D TH 4D 4C KH +4D TC KS AS 7C 3C 6D 2D 9H 6C +8C TD 5D QS 2C 7H 4C 9C 3H 9H +5H JH TS 7S TD 6H AD QD 8H 8S +5S AD 9C 8C 7C 8D 5H 9D 8S 2S +4H KH KS 9S 2S KC 5S AD 4S 7D +QS 9C QD 6H JS 5D AC 8D 2S AS +KH AC JC 3S 9D 9S 3C 9C 5S JS +AD 3C 3D KS 3S 5C 9C 8C TS 4S +JH 8D 5D 6H KD QS QD 3D 6C KC +8S JD 6C 3S 8C TC QC 3C QH JS +KC JC 8H 2S 9H 9C JH 8S 8C 9S +8S 2H QH 4D QC 9D KC AS TH 3C +8S 6H TH 7C 2H 6S 3C 3H AS 7S +QH 5S JS 4H 5H TS 8H AH AC JC +9D 8H 2S 4S TC JC 3C 7H 3H 5C +3D AD 3C 3S 4C QC AS 5D TH 8C +6S 9D 4C JS KH AH TS JD 8H AD +4C 6S 9D 7S AC 4D 3D 3S TC JD +AD 7H 6H 4H JH KC TD TS 7D 6S +8H JH TC 3S 8D 8C 9S 2C 5C 4D +2C 9D KC QH TH QS JC 9C 4H TS +QS 3C QD 8H KH 4H 8D TD 8S AC +7C 3C TH 5S 8H 8C 9C JD TC KD +QC TC JD TS 8C 3H 6H KD 7C TD +JH QS KS 9C 6D 6S AS 9H KH 6H +2H 4D AH 2D JH 6H TD 5D 4H JD +KD 8C 9S JH QD JS 2C QS 5C 7C +4S TC 7H 8D 2S 6H 7S 9C 7C KC +8C 5D 7H 4S TD QC 8S JS 4H KS +AD 8S JH 6D TD KD 7C 6C 2D 7D +JC 6H 6S JS 4H QH 9H AH 4C 3C +6H 5H AS 7C 7S 3D KH KC 5D 5C +JC 3D TD AS 4D 6D 6S QH JD KS +8C 7S 8S QH 2S JD 5C 7H AH QD +8S 3C 6H 6C 2C 8D TD 7D 4C 4D +5D QH KH 7C 2S 7H JS 6D QC QD +AD 6C 6S 7D TH 6H 2H 8H KH 4H +KS JS KD 5D 2D KH 7D 9C 8C 3D +9C 6D QD 3C KS 3S 7S AH JD 2D +AH QH AS JC 8S 8H 4C KC TH 7D +JC 5H TD 7C 5D KD 4C AD 8H JS +KC 2H AC AH 7D JH KH 5D 7S 6D +9S 5S 9C 6H 8S TD JD 9H 6C AC +7D 8S 6D TS KD 7H AC 5S 7C 5D +AH QC JC 4C TC 8C 2H TS 2C 7D +KD KC 6S 3D 7D 2S 8S 3H 5S 5C +8S 5D 8H 4C 6H KC 3H 7C 5S KD +JH 8C 3D 3C 6C KC TD 7H 7C 4C +JC KC 6H TS QS TD KS 8H 8C 9S +6C 5S 9C QH 7D AH KS KC 9S 2C +4D 4S 8H TD 9C 3S 7D 9D AS TH +6S 7D 3C 6H 5D KD 2C 5C 9D 9C +2H KC 3D AD 3H QD QS 8D JC 4S +8C 3H 9C 7C AD 5D JC 9D JS AS +5D 9H 5C 7H 6S 6C QC JC QD 9S +JC QS JH 2C 6S 9C QC 3D 4S TC +4H 5S 8D 3D 4D 2S KC 2H JS 2C +TD 3S TH KD 4D 7H JH JS KS AC +7S 8C 9S 2D 8S 7D 5C AD 9D AS +8C 7H 2S 6C TH 3H 4C 3S 8H AC +KD 5H JC 8H JD 2D 4H TD JH 5C +3D AS QH KS 7H JD 8S 5S 6D 5H +9S 6S TC QS JC 5C 5D 9C TH 8C +5H 3S JH 9H 2S 2C 6S 7S AS KS +8C QD JC QS TC QC 4H AC KH 6C +TC 5H 7D JH 4H 2H 8D JC KS 4D +5S 9C KH KD 9H 5C TS 3D 7D 2D +5H AS TC 4D 8C 2C TS 9D 3H 8D +6H 8D 2D 9H JD 6C 4S 5H 5S 6D +AD 9C JC 7D 6H 9S 6D JS 9H 3C +AD JH TC QS 4C 5D 9S 7C 9C AH +KD 6H 2H TH 8S QD KS 9D 9H AS +4H 8H 8D 5H 6C AH 5S AS AD 8S +QS 5D 4S 2H TD KS 5H AC 3H JC +9C 7D QD KD AC 6D 5H QH 6H 5S +KC AH QH 2H 7D QS 3H KS 7S JD +6C 8S 3H 6D KS QD 5D 5C 8H TC +9H 4D 4S 6S 9D KH QC 4H 6C JD +TD 2D QH 4S 6H JH KD 3C QD 8C +4S 6H 7C QD 9D AS AH 6S AD 3C +2C KC TH 6H 8D AH 5C 6D 8S 5D +TD TS 7C AD JC QD 9H 3C KC 7H +5D 4D 5S 8H 4H 7D 3H JD KD 2D +JH TD 6H QS 4S KD 5C 8S 7D 8H +AC 3D AS 8C TD 7H KH 5D 6C JD +9D KS 7C 6D QH TC JD KD AS KC +JH 8S 5S 7S 7D AS 2D 3D AD 2H +2H 5D AS 3C QD KC 6H 9H 9S 2C +9D 5D TH 4C JH 3H 8D TC 8H 9H +6H KD 2C TD 2H 6C 9D 2D JS 8C +KD 7S 3C 7C AS QH TS AD 8C 2S +QS 8H 6C JS 4C 9S QC AD TD TS +2H 7C TS TC 8C 3C 9H 2D 6D JC +TC 2H 8D JH KS 6D 3H TD TH 8H +9D TD 9H QC 5D 6C 8H 8C KC TS +2H 8C 3D AH 4D TH TC 7D 8H KC +TS 5C 2D 8C 6S KH AH 5H 6H KC +5S 5D AH TC 4C JD 8D 6H 8C 6C +KC QD 3D 8H 2D JC 9H 4H AD 2S +TD 6S 7D JS KD 4H QS 2S 3S 8C +4C 9H JH TS 3S 4H QC 5S 9S 9C +2C KD 9H JS 9S 3H JC TS 5D AC +AS 2H 5D AD 5H JC 7S TD JS 4C +2D 4S 8H 3D 7D 2C AD KD 9C TS +7H QD JH 5H JS AC 3D TH 4C 8H +6D KH KC QD 5C AD 7C 2D 4H AC +3D 9D TC 8S QD 2C JC 4H JD AH +6C TD 5S TC 8S AH 2C 5D AS AC +TH 7S 3D AS 6C 4C 7H 7D 4H AH +5C 2H KS 6H 7S 4H 5H 3D 3C 7H +3C 9S AC 7S QH 2H 3D 6S 3S 3H +2D 3H AS 2C 6H TC JS 6S 9C 6C +QH KD QD 6D AC 6H KH 2C TS 8C +8H 7D 3S 9H 5D 3H 4S QC 9S 5H +2D 9D 7H 6H 3C 8S 5H 4D 3S 4S +KD 9S 4S TC 7S QC 3S 8S 2H 7H +TC 3D 8C 3H 6C 2H 6H KS KD 4D +KC 3D 9S 3H JS 4S 8H 2D 6C 8S +6H QS 6C TC QD 9H 7D 7C 5H 4D +TD 9D 8D 6S 6C TC 5D TS JS 8H +4H KC JD 9H TC 2C 6S 5H 8H AS +JS 9C 5C 6S 9D JD 8H KC 4C 6D +4D 8D 8S 6C 7C 6H 7H 8H 5C KC +TC 3D JC 6D KS 9S 6H 7S 9C 2C +6C 3S KD 5H TS 7D 9H 9S 6H KH +3D QD 4C 6H TS AC 3S 5C 2H KD +4C AS JS 9S 7C TS 7H 9H JC KS +4H 8C JD 3H 6H AD 9S 4S 5S KS +4C 2C 7D 3D AS 9C 2S QS KC 6C +8S 5H 3D 2S AC 9D 6S 3S 4D TD +QD TH 7S TS 3D AC 7H 6C 5D QC +TC QD AD 9C QS 5C 8D KD 3D 3C +9D 8H AS 3S 7C 8S JD 2D 8D KC +4C TH AC QH JS 8D 7D 7S 9C KH +9D 8D 4C JH 2C 2S QD KD TS 4H +4D 6D 5D 2D JH 3S 8S 3H TC KH +AD 4D 2C QS 8C KD JH JD AH 5C +5C 6C 5H 2H JH 4H KS 7C TC 3H +3C 4C QC 5D JH 9C QD KH 8D TC +3H 9C JS 7H QH AS 7C 9H 5H JC +2D 5S QD 4S 3C KC 6S 6C 5C 4C +5D KH 2D TS 8S 9C AS 9S 7C 4C +7C AH 8C 8D 5S KD QH QS JH 2C +8C 9D AH 2H AC QC 5S 8H 7H 2C +QD 9H 5S QS QC 9C 5H JC TH 4H +6C 6S 3H 5H 3S 6H KS 8D AC 7S +AC QH 7H 8C 4S KC 6C 3D 3S TC +9D 3D JS TH AC 5H 3H 8S 3S TC +QD KH JS KS 9S QC 8D AH 3C AC +5H 6C KH 3S 9S JH 2D QD AS 8C +6C 4D 7S 7H 5S JC 6S 9H 4H JH +AH 5S 6H 9S AD 3S TH 2H 9D 8C +4C 8D 9H 7C QC AD 4S 9C KC 5S +9D 6H 4D TC 4C JH 2S 5D 3S AS +2H 6C 7C KH 5C AD QS TH JD 8S +3S 4S 7S AH AS KC JS 2S AD TH +JS KC 2S 7D 8C 5C 9C TS 5H 9D +7S 9S 4D TD JH JS KH 6H 5D 2C +JD JS JC TH 2D 3D QD 8C AC 5H +7S KH 5S 9D 5D TD 4S 6H 3C 2D +4S 5D AC 8D 4D 7C AD AS AH 9C +6S TH TS KS 2C QC AH AS 3C 4S +2H 8C 3S JC 5C 7C 3H 3C KH JH +7S 3H JC 5S 6H 4C 2S 4D KC 7H +4D 7C 4H 9S 8S 6S AD TC 6C JC +KH QS 3S TC 4C 8H 8S AC 3C TS +QD QS TH 3C TS 7H 7D AH TD JC +TD JD QC 4D 9S 7S TS AD 7D AC +AH 7H 4S 6D 7C 2H 9D KS JC TD +7C AH JD 4H 6D QS TS 2H 2C 5C +TC KC 8C 9S 4C JS 3C JC 6S AH +AS 7D QC 3D 5S JC JD 9D TD KH +TH 3C 2S 6H AH AC 5H 5C 7S 8H +QC 2D AC QD 2S 3S JD QS 6S 8H +KC 4H 3C 9D JS 6H 3S 8S AS 8C +7H KC 7D JD 2H JC QH 5S 3H QS +9H TD 3S 8H 7S AC 5C 6C AH 7C +8D 9H AH JD TD QS 7D 3S 9C 8S +AH QH 3C JD KC 4S 5S 5D TD KS +9H 7H 6S JH TH 4C 7C AD 5C 2D +7C KD 5S TC 9D 6S 6C 5D 2S TH +KC 9H 8D 5H 7H 4H QC 3D 7C AS +6S 8S QC TD 4S 5C TH QS QD 2S +8S 5H TH QC 9H 6S KC 7D 7C 5C +7H KD AH 4D KH 5C 4S 2D KC QH +6S 2C TD JC AS 4D 6C 8C 4H 5S +JC TC JD 5S 6S 8D AS 9D AD 3S +6D 6H 5D 5S TC 3D 7D QS 9D QD +4S 6C 8S 3S 7S AD KS 2D 7D 7C +KC QH JC AC QD 5D 8D QS 7H 7D +JS AH 8S 5H 3D TD 3H 4S 6C JH +4S QS 7D AS 9H JS KS 6D TC 5C +2D 5C 6H TC 4D QH 3D 9H 8S 6C +6D 7H TC TH 5S JD 5C 9C KS KD +8D TD QH 6S 4S 6C 8S KC 5C TC +5S 3D KS AC 4S 7D QD 4C TH 2S +TS 8H 9S 6S 7S QH 3C AH 7H 8C +4C 8C TS JS QC 3D 7D 5D 7S JH +8S 7S 9D QC AC 7C 6D 2H JH KC +JS KD 3C 6S 4S 7C AH QC KS 5H +KS 6S 4H JD QS TC 8H KC 6H AS +KH 7C TC 6S TD JC 5C 7D AH 3S +3H 4C 4H TC TH 6S 7H 6D 9C QH +7D 5H 4S 8C JS 4D 3D 8S QH KC +3H 6S AD 7H 3S QC 8S 4S 7S JS +3S JD KH TH 6H QS 9C 6C 2D QD +4S QH 4D 5H KC 7D 6D 8D TH 5S +TD AD 6S 7H KD KH 9H 5S KC JC +3H QC AS TS 4S QD KS 9C 7S KC +TS 6S QC 6C TH TC 9D 5C 5D KD +JS 3S 4H KD 4C QD 6D 9S JC 9D +8S JS 6D 4H JH 6H 6S 6C KS KH +AC 7D 5D TC 9S KH 6S QD 6H AS +AS 7H 6D QH 8D TH 2S KH 5C 5H +4C 7C 3D QC TC 4S KH 8C 2D JS +6H 5D 7S 5H 9C 9H JH 8S TH 7H +AS JS 2S QD KH 8H 4S AC 8D 8S +3H 4C TD KD 8C JC 5C QS 2D JD +TS 7D 5D 6C 2C QS 2H 3C AH KS +4S 7C 9C 7D JH 6C 5C 8H 9D QD +2S TD 7S 6D 9C 9S QS KH QH 5C +JC 6S 9C QH JH 8D 7S JS KH 2H +8D 5H TH KC 4D 4S 3S 6S 3D QS +2D JD 4C TD 7C 6D TH 7S JC AH +QS 7S 4C TH 9D TS AD 4D 3H 6H +2D 3H 7D JD 3D AS 2S 9C QC 8S +4H 9H 9C 2C 7S JH KD 5C 5D 6H +TC 9H 8H JC 3C 9S 8D KS AD KC +TS 5H JD QS QH QC 8D 5D KH AH +5D AS 8S 6S 4C AH QC QD TH 7H +3H 4H 7D 6S 4S 9H AS 8H JS 9D +JD 8C 2C 9D 7D 5H 5S 9S JC KD +KD 9C 4S QD AH 7C AD 9D AC TD +6S 4H 4S 9C 8D KS TC 9D JH 7C +5S JC 5H 4S QH AC 2C JS 2S 9S +8C 5H AS QD AD 5C 7D 8S QC TD +JC 4C 8D 5C KH QS 4D 6H 2H 2C +TH 4S 2D KC 3H QD AC 7H AD 9D +KH QD AS 8H TH KC 8D 7S QH 8C +JC 6C 7D 8C KH AD QS 2H 6S 2D +JC KH 2D 7D JS QC 5H 4C 5D AD +TS 3S AD 4S TD 2D TH 6S 9H JH +9H 2D QS 2C 4S 3D KH AS AC 9D +KH 6S 8H 4S KD 7D 9D TS QD QC +JH 5H AH KS AS AD JC QC 5S KH +5D 7D 6D KS KD 3D 7C 4D JD 3S +AC JS 8D 5H 9C 3H 4H 4D TS 2C +6H KS KH 9D 7C 2S 6S 8S 2H 3D +6H AC JS 7S 3S TD 8H 3H 4H TH +9H TC QC KC 5C KS 6H 4H AC 8S +TC 7D QH 4S JC TS 6D 6C AC KH +QH 7D 7C JH QS QD TH 3H 5D KS +3D 5S 8D JS 4C 2C KS 7H 9C 4H +5H 8S 4H TD 2C 3S QD QC 3H KC +QC JS KD 9C AD 5S 9D 7D 7H TS +8C JC KH 7C 7S 6C TS 2C QD TH +5S 9D TH 3C 7S QH 8S 9C 2H 5H +5D 9H 6H 2S JS KH 3H 7C 2H 5S +JD 5D 5S 2C TC 2S 6S 6C 3C 8S +4D KH 8H 4H 2D KS 3H 5C 2S 9H +3S 2D TD 7H 8S 6H JD KC 9C 8D +6S QD JH 7C 9H 5H 8S 8H TH TD +QS 7S TD 7D TS JC KD 7C 3C 2C +3C JD 8S 4H 2D 2S TD AS 4D AC +AH KS 6C 4C 4S 7D 8C 9H 6H AS +5S 3C 9S 2C QS KD 4D 4S AC 5D +2D TS 2C JS KH QH 5D 8C AS KC +KD 3H 6C TH 8S 7S KH 6H 9S AC +6H 7S 6C QS AH 2S 2H 4H 5D 5H +5H JC QD 2C 2S JD AS QC 6S 7D +6C TC AS KD 8H 9D 2C 7D JH 9S +2H 4C 6C AH 8S TD 3H TH 7C TS +KD 4S TS 6C QH 8D 9D 9C AH 7D +6D JS 5C QD QC 9C 5D 8C 2H KD +3C QH JH AD 6S AH KC 8S 6D 6H +3D 7C 4C 7S 5S 3S 6S 5H JC 3C +QH 7C 5H 3C 3S 8C TS 4C KD 9C +QD 3S 7S 5H 7H QH JC 7C 8C KD +3C KD KH 2S 4C TS AC 6S 2C 7C +2C KH 3C 4C 6H 4D 5H 5S 7S QD +4D 7C 8S QD TS 9D KS 6H KD 3C +QS 4D TS 7S 4C 3H QD 8D 9S TC +TS QH AC 6S 3C 9H 9D QS 8S 6H +3S 7S 5D 4S JS 2D 6C QH 6S TH +4C 4H AS JS 5D 3D TS 9C AC 8S +6S 9C 7C 3S 5C QS AD AS 6H 3C +9S 8C 7H 3H 6S 7C AS 9H JD KH +3D 3H 7S 4D 6C 7C AC 2H 9C TH +4H 5S 3H AC TC TH 9C 9H 9S 8D +8D 9H 5H 4D 6C 2H QD 6S 5D 3S +4C 5C JD QS 4D 3H TH AC QH 8C +QC 5S 3C 7H AD 4C KS 4H JD 6D +QS AH 3H KS 9H 2S JS JH 5H 2H +2H 5S TH 6S TS 3S KS 3C 5H JS +2D 9S 7H 3D KC JH 6D 7D JS TD +AC JS 8H 2C 8C JH JC 2D TH 7S +5D 9S 8H 2H 3D TC AH JC KD 9C +9D QD JC 2H 6D KH TS 9S QH TH +2C 8D 4S JD 5H 3H TH TC 9C KC +AS 3D 9H 7D 4D TH KH 2H 7S 3H +4H 7S KS 2S JS TS 8S 2H QD 8D +5S 6H JH KS 8H 2S QC AC 6S 3S +JC AS AD QS 8H 6C KH 4C 4D QD +2S 3D TS TD 9S KS 6S QS 5C 8D +3C 6D 4S QC KC JH QD TH KH AD +9H AH 4D KS 2S 8D JH JC 7C QS +2D 6C TH 3C 8H QD QH 2S 3S KS +6H 5D 9S 4C TS TD JS QD 9D JD +5H 8H KH 8S KS 7C TD AD 4S KD +2C 7C JC 5S AS 6C 7D 8S 5H 9C +6S QD 9S TS KH QS 5S QH 3C KC +7D 3H 3C KD 5C AS JH 7H 6H JD +9D 5C 9H KC 8H KS 4S AD 4D 2S +3S JD QD 8D 2S 7C 5S 6S 5H TS +6D 9S KC TD 3S 6H QD JD 5C 8D +5H 9D TS KD 8D 6H TD QC 4C 7D +6D 4S JD 9D AH 9S AS TD 9H QD +2D 5S 2H 9C 6H 9S TD QC 7D TC +3S 2H KS TS 2C 9C 8S JS 9D 7D +3C KC 6D 5D 6C 6H 8S AS 7S QS +JH 9S 2H 8D 4C 8H 9H AD TH KH +QC AS 2S JS 5C 6H KD 3H 7H 2C +QD 8H 2S 8D 3S 6D AH 2C TC 5C +JD JS TS 8S 3H 5D TD KC JC 6H +6S QS TC 3H 5D AH JC 7C 7D 4H +7C 5D 8H 9C 2H 9H JH KH 5S 2C +9C 7H 6S TH 3S QC QD 4C AC JD +2H 5D 9S 7D KC 3S QS 2D AS KH +2S 4S 2H 7D 5C TD TH QH 9S 4D +6D 3S TS 6H 4H KS 9D 8H 5S 2D +9H KS 4H 3S 5C 5D KH 6H 6S JS +KC AS 8C 4C JC KH QC TH QD AH +6S KH 9S 2C 5H TC 3C 7H JC 4D +JD 4S 6S 5S 8D 7H 7S 4D 4C 2H +7H 9H 5D KH 9C 7C TS TC 7S 5H +4C 8D QC TS 4S 9H 3D AD JS 7C +8C QS 5C 5D 3H JS AH KC 4S 9D +TS JD 8S QS TH JH KH 2D QD JS +JD QC 5D 6S 9H 3S 2C 8H 9S TS +2S 4C AD 7H JC 5C 2D 6D 4H 3D +7S JS 2C 4H 8C AD QD 9C 3S TD +JD TS 4C 6H 9H 7D QD 6D 3C AS +AS 7C 4C 6S 5D 5S 5C JS QC 4S +KD 6S 9S 7C 3C 5S 7D JH QD JS +4S 7S JH 2C 8S 5D 7H 3D QH AD +TD 6H 2H 8D 4H 2D 7C AD KH 5D +TS 3S 5H 2C QD AH 2S 5C KH TD +KC 4D 8C 5D AS 6C 2H 2S 9H 7C +KD JS QC TS QS KH JH 2C 5D AD +3S 5H KC 6C 9H 3H 2H AD 7D 7S +7S JS JH KD 8S 7D 2S 9H 7C 2H +9H 2D 8D QC 6S AD AS 8H 5H 6C +2S 7H 6C 6D 7D 8C 5D 9D JC 3C +7C 9C 7H JD 2H KD 3S KH AD 4S +QH AS 9H 4D JD KS KD TS KH 5H +4C 8H 5S 3S 3D 7D TD AD 7S KC +JS 8S 5S JC 8H TH 9C 4D 5D KC +7C 5S 9C QD 2C QH JS 5H 8D KH +TD 2S KS 3D AD KC 7S TC 3C 5D +4C 2S AD QS 6C 9S QD TH QH 5C +8C AD QS 2D 2S KC JD KS 6C JC +8D 4D JS 2H 5D QD 7S 7D QH TS +6S 7H 3S 8C 8S 9D QS 8H 6C 9S +4S TC 2S 5C QD 4D QS 6D TH 6S +3S 5C 9D 6H 8D 4C 7D TC 7C TD +AH 6S AS 7H 5S KD 3H 5H AC 4C +8D 8S AH KS QS 2C AD 6H 7D 5D +6H 9H 9S 2H QS 8S 9C 5D 2D KD +TS QC 5S JH 7D 7S TH 9S 9H AC +7H 3H 6S KC 4D 6D 5C 4S QD TS +TD 2S 7C QD 3H JH 9D 4H 7S 7H +KS 3D 4H 5H TC 2S AS 2D 6D 7D +8H 3C 7H TD 3H AD KC TH 9C KH +TC 4C 2C 9S 9D 9C 5C 2H JD 3C +3H AC TS 5D AD 8D 6H QC 6S 8C +2S TS 3S JD 7H 8S QH 4C 5S 8D +AC 4S 6C 3C KH 3D 7C 2D 8S 2H +4H 6C 8S TH 2H 4S 8H 9S 3H 7S +7C 4C 9C 2C 5C AS 5D KD 4D QH +9H 4H TS AS 7D 8D 5D 9S 8C 2H +QC KD AC AD 2H 7S AS 3S 2D 9S +2H QC 8H TC 6D QD QS 5D KH 3C +TH JD QS 4C 2S 5S AD 7H 3S AS +7H JS 3D 6C 3S 6D AS 9S AC QS +9C TS AS 8C TC 8S 6H 9D 8D 6C +4D JD 9C KC 7C 6D KS 3S 8C AS +3H 6S TC 8D TS 3S KC 9S 7C AS +8C QC 4H 4S 8S 6C 3S TC AH AC +4D 7D 5C AS 2H 6S TS QC AD TC +QD QC 8S 4S TH 3D AH TS JH 4H +5C 2D 9S 2C 3H 3C 9D QD QH 7D +KC 9H 6C KD 7S 3C 4D AS TC 2D +3D JS 4D 9D KS 7D TH QC 3H 3C +8D 5S 2H 9D 3H 8C 4C 4H 3C TH +JC TH 4S 6S JD 2D 4D 6C 3D 4C +TS 3S 2D 4H AC 2C 6S 2H JH 6H +TD 8S AD TC AH AC JH 9S 6S 7S +6C KC 4S JD 8D 9H 5S 7H QH AH +KD 8D TS JH 5C 5H 3H AD AS JS +2D 4H 3D 6C 8C 7S AD 5D 5C 8S +TD 5D 7S 9C 4S 5H 6C 8C 4C 8S +JS QH 9C AS 5C QS JC 3D QC 7C +JC 9C KH JH QS QC 2C TS 3D AD +5D JH AC 5C 9S TS 4C JD 8C KS +KC AS 2D KH 9H 2C 5S 4D 3D 6H +TH AH 2D 8S JC 3D 8C QH 7S 3S +8H QD 4H JC AS KH KS 3C 9S 6D +9S QH 7D 9C 4S AC 7H KH 4D KD +AH AD TH 6D 9C 9S KD KS QH 4H +QD 6H 9C 7C QS 6D 6S 9D 5S JH +AH 8D 5H QD 2H JC KS 4H KH 5S +5C 2S JS 8D 9C 8C 3D AS KC AH +JD 9S 2H QS 8H 5S 8C TH 5C 4C +QC QS 8C 2S 2C 3S 9C 4C KS KH +2D 5D 8S AH AD TD 2C JS KS 8C +TC 5S 5H 8H QC 9H 6H JD 4H 9S +3C JH 4H 9H AH 4S 2H 4C 8D AC +8S TH 4D 7D 6D QD QS 7S TC 7C +KH 6D 2D JD 5H JS QD JH 4H 4S +9C 7S JH 4S 3S TS QC 8C TC 4H +QH 9D 4D JH QS 3S 2C 7C 6C 2D +4H 9S JD 5C 5H AH 9D TS 2D 4C +KS JH TS 5D 2D AH JS 7H AS 8D +JS AH 8C AD KS 5S 8H 2C 6C TH +2H 5D AD AC KS 3D 8H TS 6H QC +6D 4H TS 9C 5H JS JH 6S JD 4C +JH QH 4H 2C 6D 3C 5D 4C QS KC +6H 4H 6C 7H 6S 2S 8S KH QC 8C +3H 3D 5D KS 4H TD AD 3S 4D TS +5S 7C 8S 7D 2C KS 7S 6C 8C JS +5D 2H 3S 7C 5C QD 5H 6D 9C 9H +JS 2S KD 9S 8D TD TS AC 8C 9D +5H QD 2S AC 8C 9H KS 7C 4S 3C +KH AS 3H 8S 9C JS QS 4S AD 4D +AS 2S TD AD 4D 9H JC 4C 5H QS +5D 7C 4H TC 2D 6C JS 4S KC 3S +4C 2C 5D AC 9H 3D JD 8S QS QH +2C 8S 6H 3C QH 6D TC KD AC AH +QC 6C 3S QS 4S AC 8D 5C AD KH +5S 4C AC KH AS QC 2C 5C 8D 9C +8H JD 3C KH 8D 5C 9C QD QH 9D +7H TS 2C 8C 4S TD JC 9C 5H QH +JS 4S 2C 7C TH 6C AS KS 7S JD +JH 7C 9H 7H TC 5H 3D 6D 5D 4D +2C QD JH 2H 9D 5S 3D TD AD KS +JD QH 3S 4D TH 7D 6S QS KS 4H +TC KS 5S 8D 8H AD 2S 2D 4C JH +5S JH TC 3S 2D QS 9D 4C KD 9S +AC KH 3H AS 9D KC 9H QD 6C 6S +9H 7S 3D 5C 7D KC TD 8H 4H 6S +3C 7H 8H TC QD 4D 7S 6S QH 6C +6D AD 4C QD 6C 5D 7D 9D KS TS +JH 2H JD 9S 7S TS KH 8D 5D 8H +2D 9S 4C 7D 9D 5H QD 6D AC 6S +7S 6D JC QD JH 4C 6S QS 2H 7D +8C TD JH KD 2H 5C QS 2C JS 7S +TC 5H 4H JH QD 3S 5S 5D 8S KH +KS KH 7C 2C 5D JH 6S 9C 6D JC +5H AH JD 9C JS KC 2H 6H 4D 5S +AS 3C TH QC 6H 9C 8S 8C TD 7C +KC 2C QD 9C KH 4D 7S 3C TS 9H +9C QC 2S TS 8C TD 9S QD 3S 3C +4D 9D TH JH AH 6S 2S JD QH JS +QD 9H 6C KD 7D 7H 5D 6S 8H AH +8H 3C 4S 2H 5H QS QH 7S 4H AC +QS 3C 7S 9S 4H 3S AH KS 9D 7C +AD 5S 6S 2H 2D 5H TC 4S 3C 8C +QH TS 6S 4D JS KS JH AS 8S 6D +2C 8S 2S TD 5H AS TC TS 6C KC +KC TS 8H 2H 3H 7C 4C 5S TH TD +KD AD KH 7H 7S 5D 5H 5S 2D 9C +AD 9S 3D 7S 8C QC 7C 9C KD KS +3C QC 9S 8C 4D 5C AS QD 6C 2C +2H KC 8S JD 7S AC 8D 5C 2S 4D +9D QH 3D 2S TC 3S KS 3C 9H TD +KD 6S AC 2C 7H 5H 3S 6C 6H 8C +QH TC 8S 6S KH TH 4H 5D TS 4D +8C JS 4H 6H 2C 2H 7D AC QD 3D +QS KC 6S 2D 5S 4H TD 3H JH 4C +7S 5H 7H 8H KH 6H QS TH KD 7D +5H AD KD 7C KH 5S TD 6D 3C 6C +8C 9C 5H JD 7C KC KH 7H 2H 3S +7S 4H AD 4D 8S QS TH 3D 7H 5S +8D TC KS KD 9S 6D AD JD 5C 2S +7H 8H 6C QD 2H 6H 9D TC 9S 7C +8D 6D 4C 7C 6C 3C TH KH JS JH +5S 3S 8S JS 9H AS AD 8H 7S KD +JH 7C 2C KC 5H AS AD 9C 9S JS +AD AC 2C 6S QD 7C 3H TH KS KD +9D JD 4H 8H 4C KH 7S TS 8C KC +3S 5S 2H 7S 6H 7D KS 5C 6D AD +5S 8C 9H QS 7H 7S 2H 6C 7D TD +QS 5S TD AC 9D KC 3D TC 2D 4D +TD 2H 7D JD QD 4C 7H 5D KC 3D +4C 3H 8S KD QH 5S QC 9H TC 5H +9C QD TH 5H TS 5C 9H AH QH 2C +4D 6S 3C AC 6C 3D 2C 2H TD TH +AC 9C 5D QC 4D AD 8D 6D 8C KC +AD 3C 4H AC 8D 8H 7S 9S TD JC +4H 9H QH JS 2D TH TD TC KD KS +5S 6S 9S 8D TH AS KH 5H 5C 8S +JD 2S 9S 6S 5S 8S 5D 7S 7H 9D +5D 8C 4C 9D AD TS 2C 7D KD TC +8S QS 4D KC 5C 8D 4S KH JD KD +AS 5C AD QH 7D 2H 9S 7H 7C TC +2S 8S JD KH 7S 6C 6D AD 5D QC +9H 6H 3S 8C 8H AH TC 4H JS TD +2C TS 4D 7H 2D QC 9C 5D TH 7C +6C 8H QC 5D TS JH 5C 5H 9H 4S +2D QC 7H AS JS 8S 2H 4C 4H 8D +JS 6S AC KD 3D 3C 4S 7H TH KC +QH KH 6S QS 5S 4H 3C QD 3S 3H +7H AS KH 8C 4H 9C 5S 3D 6S TS +9C 7C 3H 5S QD 2C 3D AD AC 5H +JH TD 2D 4C TS 3H KH AD 3S 7S +AS 4C 5H 4D 6S KD JC 3C 6H 2D +3H 6S 8C 2D TH 4S AH QH AD 5H +7C 2S 9H 7H KC 5C 6D 5S 3H JC +3C TC 9C 4H QD TD JH 6D 9H 5S +7C 6S 5C 5D 6C 4S 7H 9H 6H AH +AD 2H 7D KC 2C 4C 2S 9S 7H 3S +TH 4C 8S 6S 3S AD KS AS JH TD +5C TD 4S 4D AD 6S 5D TC 9C 7D +8H 3S 4D 4S 5S 6H 5C AC 3H 3D +9H 3C AC 4S QS 8S 9D QH 5H 4D +JC 6C 5H TS AC 9C JD 8C 7C QD +8S 8H 9C JD 2D QC QH 6H 3C 8D +KS JS 2H 6H 5H QH QS 3H 7C 6D +TC 3H 4S 7H QC 2H 3S 8C JS KH +AH 8H 5S 4C 9H JD 3H 7S JC AC +3C 2D 4C 5S 6C 4S QS 3S JD 3D +5H 2D TC AH KS 6D 7H AD 8C 6H +6C 7S 3C JD 7C 8H KS KH AH 6D +AH 7D 3H 8H 8S 7H QS 5H 9D 2D +JD AC 4H 7S 8S 9S KS AS 9D QH +7S 2C 8S 5S JH QS JC AH KD 4C +AH 2S 9H 4H 8D TS TD 6H QH JD +4H JC 3H QS 6D 7S 9C 8S 9D 8D +5H TD 4S 9S 4C 8C 8D 7H 3H 3D +QS KH 3S 2C 2S 3C 7S TD 4S QD +7C TD 4D 5S KH AC AS 7H 4C 6C +2S 5H 6D JD 9H QS 8S 2C 2H TD +2S TS 6H 9H 7S 4H JC 4C 5D 5S +2C 5H 7D 4H 3S QH JC JS 6D 8H +4C QH 7C QD 3S AD TH 8S 5S TS +9H TC 2S TD JC 7D 3S 3D TH QH +7D 4C 8S 5C JH 8H 6S 3S KC 3H +JC 3H KH TC QH TH 6H 2C AC 5H +QS 2H 9D 2C AS 6S 6C 2S 8C 8S +9H 7D QC TH 4H KD QS AC 7S 3C +4D JH 6S 5S 8H KS 9S QC 3S AS +JD 2D 6S 7S TC 9H KC 3H 7D KD +2H KH 7C 4D 4S 3H JS QD 7D KC +4C JC AS 9D 3C JS 6C 8H QD 4D +AH JS 3S 6C 4C 3D JH 6D 9C 9H +9H 2D 8C 7H 5S KS 6H 9C 2S TC +6C 8C AD 7H 6H 3D KH AS 5D TH +KS 8C 3S TS 8S 4D 5S 9S 6C 4H +9H 4S 4H 5C 7D KC 2D 2H 9D JH +5C JS TC 9D 9H 5H 7S KH JC 6S +7C 9H 8H 4D JC KH JD 2H TD TC +8H 6C 2H 2C KH 6H 9D QS QH 5H +AC 7D 2S 3D QD JC 2D 8D JD JH +2H JC 2D 7H 2C 3C 8D KD TD 4H +3S 4H 6D 8D TS 3H TD 3D 6H TH +JH JC 3S AC QH 9H 7H 8S QC 2C +7H TD QS 4S 8S 9C 2S 5D 4D 2H +3D TS 3H 2S QC 8H 6H KC JC KS +5D JD 7D TC 8C 6C 9S 3D 8D AC +8H 6H JH 6C 5D 8D 8S 4H AD 2C +9D 4H 2D 2C 3S TS AS TC 3C 5D +4D TH 5H KS QS 6C 4S 2H 3D AD +5C KC 6H 2C 5S 3C 4D 2D 9H 9S +JD 4C 3H TH QH 9H 5S AH 8S AC +7D 9S 6S 2H TD 9C 4H 8H QS 4C +3C 6H 5D 4H 8C 9C KC 6S QD QS +3S 9H KD TC 2D JS 8C 6S 4H 4S +2S 4C 8S QS 6H KH 3H TH 8C 5D +2C KH 5S 3S 7S 7H 6C 9D QD 8D +8H KS AC 2D KH TS 6C JS KC 7H +9C KS 5C TD QC AH 6C 5H 9S 7C +5D 4D 3H 4H 6S 7C 7S AH QD TD +2H 7D QC 6S TC TS AH 7S 9D 3H +TH 5H QD 9S KS 7S 7C 6H 8C TD +TH 2D 4D QC 5C 7D JD AH 9C 4H +4H 3H AH 8D 6H QC QH 9H 2H 2C +2D AD 4C TS 6H 7S TH 4H QS TD +3C KD 2H 3H QS JD TC QC 5D 8H +KS JC QD TH 9S KD 8D 8C 2D 9C +3C QD KD 6D 4D 8D AH AD QC 8S +8H 3S 9D 2S 3H KS 6H 4C 7C KC +TH 9S 5C 3D 7D 6H AC 7S 4D 2C +5C 3D JD 4D 2D 6D 5H 9H 4C KH +AS 7H TD 6C 2H 3D QD KS 4C 4S +JC 3C AC 7C JD JS 8H 9S QC 5D +JD 6S 5S 2H AS 8C 7D 5H JH 3D +8D TC 5S 9S 8S 3H JC 5H 7S AS +5C TD 3D 7D 4H 8D 7H 4D 5D JS +QS 9C KS TD 2S 8S 5C 2H 4H AS +TH 7S 4H 7D 3H JD KD 5D 2S KC +JD 7H 4S 8H 4C JS 6H QH 5S 4H +2C QS 8C 5S 3H QC 2S 6C QD AD +8C 3D JD TC 4H 2H AD 5S AC 2S +5D 2C JS 2D AD 9D 3D 4C 4S JH +8D 5H 5D 6H 7S 4D KS 9D TD JD +3D 6D 9C 2S AS 7D 5S 5C 8H JD +7C 8S 3S 6S 5H JD TC AD 7H 7S +2S 9D TS 4D AC 8D 6C QD JD 3H +9S KH 2C 3C AC 3D 5H 6H 8D 5D +KS 3D 2D 6S AS 4C 2S 7C 7H KH +AC 2H 3S JC 5C QH 4D 2D 5H 7S +TS AS JD 8C 6H JC 8S 5S 2C 5D +7S QH 7H 6C QC 8H 2D 7C JD 2S +2C QD 2S 2H JC 9C 5D 2D JD JH +7C 5C 9C 8S 7D 6D 8D 6C 9S JH +2C AD 6S 5H 3S KS 7S 9D KH 4C +7H 6C 2C 5C TH 9D 8D 3S QC AH +5S KC 6H TC 5H 8S TH 6D 3C AH +9C KD 4H AD TD 9S 4S 7D 6H 5D +7H 5C 5H 6D AS 4C KD KH 4H 9D +3C 2S 5C 6C JD QS 2H 9D 7D 3H +AC 2S 6S 7S JS QD 5C QS 6H AD +5H TH QC 7H TC 3S 7C 6D KC 3D +4H 3D QC 9S 8H 2C 3S JC KS 5C +4S 6S 2C 6H 8S 3S 3D 9H 3H JS +4S 8C 4D 2D 8H 9H 7D 9D AH TS +9S 2C 9H 4C 8D AS 7D 3D 6D 5S +6S 4C 7H 8C 3H 5H JC AH 9D 9C +2S 7C 5S JD 8C 3S 3D 4D 7D 6S +3C KC 4S 5D 7D 3D JD 7H 3H 4H +9C 9H 4H 4D TH 6D QD 8S 9S 7S +2H AC 8S 4S AD 8C 2C AH 7D TC +TS 9H 3C AD KS TC 3D 8C 8H JD +QC 8D 2C 3C 7D 7C JD 9H 9C 6C +AH 6S JS JH 5D AS QC 2C JD TD +9H KD 2H 5D 2D 3S 7D TC AH TS +TD 8H AS 5D AH QC AC 6S TC 5H +KS 4S 7H 4D 8D 9C TC 2H 6H 3H +3H KD 4S QD QH 3D 8H 8C TD 7S +8S JD TC AH JS QS 2D KH KS 4D +3C AD JC KD JS KH 4S TH 9H 2C +QC 5S JS 9S KS AS 7C QD 2S JD +KC 5S QS 3S 2D AC 5D 9H 8H KS +6H 9C TC AD 2C 6D 5S JD 6C 7C +QS KH TD QD 2C 3H 8S 2S QC AH +9D 9H JH TC QH 3C 2S JS 5C 7H +6C 3S 3D 2S 4S QD 2D TH 5D 2C +2D 6H 6D 2S JC QH AS 7H 4H KH +5H 6S KS AD TC TS 7C AC 4S 4H +AD 3C 4H QS 8C 9D KS 2H 2D 4D +4S 9D 6C 6D 9C AC 8D 3H 7H KD +JC AH 6C TS JD 6D AD 3S 5D QD +JC JH JD 3S 7S 8S JS QC 3H 4S +JD TH 5C 2C AD JS 7H 9S 2H 7S +8D 3S JH 4D QC AS JD 2C KC 6H +2C AC 5H KD 5S 7H QD JH AH 2D +JC QH 8D 8S TC 5H 5C AH 8C 6C +3H JS 8S QD JH 3C 4H 6D 5C 3S +6D 4S 4C AH 5H 5S 3H JD 7C 8D +8H AH 2H 3H JS 3C 7D QC 4H KD +6S 2H KD 5H 8H 2D 3C 8S 7S QD +2S 7S KC QC AH TC QS 6D 4C 8D +5S 9H 2C 3S QD 7S 6C 2H 7C 9D +3C 6C 5C 5S JD JC KS 3S 5D TS +7C KS 6S 5S 2S 2D TC 2H 5H QS +AS 7H 6S TS 5H 9S 9D 3C KD 2H +4S JS QS 3S 4H 7C 2S AC 6S 9D +8C JH 2H 5H 7C 5D QH QS KH QC +3S TD 3H 7C KC 8D 5H 8S KH 8C +4H KH JD TS 3C 7H AS QC JS 5S +AH 9D 2C 8D 4D 2D 6H 6C KC 6S +2S 6H 9D 3S 7H 4D KH 8H KD 3D +9C TC AC JH KH 4D JD 5H TD 3S +7S 4H 9D AS 4C 7D QS 9S 2S KH +3S 8D 8S KS 8C JC 5C KH 2H 5D +8S QH 2C 4D KC JS QC 9D AC 6H +8S 8C 7C JS JD 6S 4C 9C AC 4S +QH 5D 2C 7D JC 8S 2D JS JH 4C +JS 4C 7S TS JH KC KH 5H QD 4S +QD 8C 8D 2D 6S TD 9D AC QH 5S +QH QC JS 3D 3C 5C 4H KH 8S 7H +7C 2C 5S JC 8S 3H QC 5D 2H KC +5S 8D KD 6H 4H QD QH 6D AH 3D +7S KS 6C 2S 4D AC QS 5H TS JD +7C 2D TC 5D QS AC JS QC 6C KC +2C KS 4D 3H TS 8S AD 4H 7S 9S +QD 9H QH 5H 4H 4D KH 3S JC AD +4D AC KC 8D 6D 4C 2D KH 2C JD +2C 9H 2D AH 3H 6D 9C 7D TC KS +8C 3H KD 7C 5C 2S 4S 5H AS AH +TH JD 4H KD 3H TC 5C 3S AC KH +6D 7H AH 7S QC 6H 2D TD JD AS +JH 5D 7H TC 9S 7D JC AS 5S KH +2H 8C AD TH 6H QD KD 9H 6S 6C +QH KC 9D 4D 3S JS JH 4H 2C 9H +TC 7H KH 4H JC 7D 9S 3H QS 7S +AD 7D JH 6C 7H 4H 3S 3H 4D QH +JD 2H 5C AS 6C QC 4D 3C TC JH +AC JD 3H 6H 4C JC AD 7D 7H 9H +4H TC TS 2C 8C 6S KS 2H JD 9S +4C 3H QS QC 9S 9H 6D KC 9D 9C +5C AD 8C 2C QH TH QD JC 8D 8H +QC 2C 2S QD 9C 4D 3S 8D JH QS +9D 3S 2C 7S 7C JC TD 3C TC 9H +3C TS 8H 5C 4C 2C 6S 8D 7C 4H +KS 7H 2H TC 4H 2C 3S AS AH QS +8C 2D 2H 2C 4S 4C 6S 7D 5S 3S +TH QC 5D TD 3C QS KD KC KS AS +4D AH KD 9H KS 5C 4C 6H JC 7S +KC 4H 5C QS TC 2H JC 9S AH QH +4S 9H 3H 5H 3C QD 2H QC JH 8H +5D AS 7H 2C 3D JH 6H 4C 6S 7D +9C JD 9H AH JS 8S QH 3H KS 8H +3S AC QC TS 4D AD 3D AH 8S 9H +7H 3H QS 9C 9S 5H JH JS AH AC +8D 3C JD 2H AC 9C 7H 5S 4D 8H +7C JH 9H 6C JS 9S 7H 8C 9D 4H +2D AS 9S 6H 4D JS JH 9H AD QD +6H 7S JH KH AH 7H TD 5S 6S 2C +8H JH 6S 5H 5S 9D TC 4C QC 9S +7D 2C KD 3H 5H AS QD 7H JS 4D +TS QH 6C 8H TH 5H 3C 3H 9C 9D +AD KH JS 5D 3H AS AC 9S 5C KC +2C KH 8C JC QS 6D AH 2D KC TC +9D 3H 2S 7C 4D 6D KH KS 8D 7D +9H 2S TC JH AC QC 3H 5S 3S 8H +3S AS KD 8H 4C 3H 7C JH QH TS +7S 6D 7H 9D JH 4C 3D 3S 6C AS +4S 2H 2C 4C 8S 5H KC 8C QC QD +3H 3S 6C QS QC 2D 6S 5D 2C 9D +2H 8D JH 2S 3H 2D 6C 5C 7S AD +9H JS 5D QH 8S TS 2H 7S 6S AD +6D QC 9S 7H 5H 5C 7D KC JD 4H +QC 5S 9H 9C 4D 6S KS 2S 4C 7C +9H 7C 4H 8D 3S 6H 5C 8H JS 7S +2D 6H JS TD 4H 4D JC TH 5H KC +AC 7C 8D TH 3H 9S 2D 4C KC 4D +KD QS 9C 7S 3D KS AD TS 4C 4H +QH 9C 8H 2S 7D KS 7H 5D KD 4C +9C 2S 2H JC 6S 6C TC QC JH 5C +7S AC 8H KC 8S 6H QS JC 3D 6S +JS 2D JH 8C 4S 6H 8H 6D 5D AD +6H 7D 2S 4H 9H 7C AS AC 8H 5S +3C JS 4S 6D 5H 2S QH 6S 9C 2C +3D 5S 6S 9S 4C QS 8D QD 8S TC +9C 3D AH 9H 5S 2C 7D AD JC 3S +7H TC AS 3C 6S 6D 7S KH KC 9H +3S TC 8H 6S 5H JH 8C 7D AC 2S +QD 9D 9C 3S JC 8C KS 8H 5D 4D +JS AH JD 6D 9D 8C 9H 9S 8H 3H +2D 6S 4C 4D 8S AD 4S TC AH 9H +TS AC QC TH KC 6D 4H 7S 8C 2H +3C QD JS 9D 5S JC AH 2H TS 9H +3H 4D QH 5D 9C 5H 7D 4S JC 3S +8S TH 3H 7C 2H JD JS TS AC 8D +9C 2H TD KC JD 2S 8C 5S AD 2C +3D KD 7C 5H 4D QH QD TC 6H 7D +7H 2C KC 5S KD 6H AH QC 7S QH +6H 5C AC 5H 2C 9C 2D 7C TD 2S +4D 9D AH 3D 7C JD 4H 8C 4C KS +TH 3C JS QH 8H 4C AS 3D QS QC +4D 7S 5H JH 6D 7D 6H JS KH 3C +QD 8S 7D 2H 2C 7C JC 2S 5H 8C +QH 8S 9D TC 2H AD 7C 8D QD 6S +3S 7C AD 9H 2H 9S JD TS 4C 2D +3S AS 4H QC 2C 8H 8S 7S TD TC +JH TH TD 3S 4D 4H 5S 5D QS 2C +8C QD QH TC 6D 4S 9S 9D 4H QC +8C JS 9D 6H JD 3H AD 6S TD QC +KC 8S 3D 7C TD 7D 8D 9H 4S 3S +6C 4S 3D 9D KD TC KC KS AC 5S +7C 6S QH 3D JS KD 6H 6D 2D 8C +JD 2S 5S 4H 8S AC 2D 6S TS 5C +5H 8C 5S 3C 4S 3D 7C 8D AS 3H +AS TS 7C 3H AD 7D JC QS 6C 6H +3S 9S 4C AC QH 5H 5D 9H TS 4H +6C 5C 7H 7S TD AD JD 5S 2H 2S +7D 6C KC 3S JD 8D 8S TS QS KH +8S QS 8D 6C TH AC AH 2C 8H 9S +7H TD KH QH 8S 3D 4D AH JD AS +TS 3D 2H JC 2S JH KH 6C QC JS +KC TH 2D 6H 7S 2S TC 8C 9D QS +3C 9D 6S KH 8H 6D 5D TH 2C 2H +6H TC 7D AD 4D 8S TS 9H TD 7S +JS 6D JD JC 2H AC 6C 3D KH 8D +KH JD 9S 5D 4H 4C 3H 7S QS 5C +4H JD 5D 3S 3C 4D KH QH QS 7S +JD TS 8S QD AH 4C 6H 3S 5S 2C +QS 3D JD AS 8D TH 7C 6S QC KS +7S 2H 8C QC 7H AC 6D 2D TH KH +5S 6C 7H KH 7D AH 8C 5C 7S 3D +3C KD AD 7D 6C 4D KS 2D 8C 4S +7C 8D 5S 2D 2S AH AD 2C 9D TD +3C AD 4S KS JH 7C 5C 8C 9C TH +AS TD 4D 7C JD 8C QH 3C 5H 9S +3H 9C 8S 9S 6S QD KS AH 5H JH +QC 9C 5S 4H 2H TD 7D AS 8C 9D +8C 2C 9D KD TC 7S 3D KH QC 3C +4D AS 4C QS 5S 9D 6S JD QH KS +6D AH 6C 4C 5H TS 9H 7D 3D 5S +QS JD 7C 8D 9C AC 3S 6S 6C KH +8H JH 5D 9S 6D AS 6S 3S QC 7H +QD AD 5C JH 2H AH 4H AS KC 2C +JH 9C 2C 6H 2D JS 5D 9H KC 6D +7D 9D KD TH 3H AS 6S QC 6H AD +JD 4H 7D KC 3H JS 3C TH 3D QS +4C 3H 8C QD 5H 6H AS 8H AD JD +TH 8S KD 5D QC 7D JS 5S 5H TS +7D KC 9D QS 3H 3C 6D TS 7S AH +7C 4H 7H AH QC AC 4D 5D 6D TH +3C 4H 2S KD 8H 5H JH TC 6C JD +4S 8C 3D 4H JS TD 7S JH QS KD +7C QC KD 4D 7H 6S AD TD TC KH +5H 9H KC 3H 4D 3D AD 6S QD 6H +TH 7C 6H TS QH 5S 2C KC TD 6S +7C 4D 5S JD JH 7D AC KD KH 4H +7D 6C 8D 8H 5C JH 8S QD TH JD +8D 7D 6C 7C 9D KD AS 5C QH JH +9S 2C 8C 3C 4C KS JH 2D 8D 4H +7S 6C JH KH 8H 3H 9D 2D AH 6D +4D TC 9C 8D 7H TD KS TH KD 3C +JD 9H 8D QD AS KD 9D 2C 2S 9C +8D 3H 5C 7H KS 5H QH 2D 8C 9H +2D TH 6D QD 6C KC 3H 3S AD 4C +4H 3H JS 9D 3C TC 5H QH QC JC +3D 5C 6H 3S 3C JC 5S 7S 2S QH +AC 5C 8C 4D 5D 4H 2S QD 3C 3H +2C TD AH 9C KD JS 6S QD 4C QC +QS 8C 3S 4H TC JS 3H 7C JC AD +5H 4D 9C KS JC TD 9S TS 8S 9H +QD TS 7D AS AC 2C TD 6H 8H AH +6S AD 8C 4S 9H 8D 9D KH 8S 3C +QS 4D 2D 7S KH JS JC AD 4C 3C +QS 9S 7H KC TD TH 5H JS AC JH +6D AC 2S QS 7C AS KS 6S KH 5S +6D 8H KH 3C QS 2H 5C 9C 9D 6C +JS 2C 4C 6H 7D JC AC QD TD 3H +4H QC 8H JD 4C KD KS 5C KC 7S +6D 2D 3H 2S QD 5S 7H AS TH 6S +AS 6D 8D 2C 8S TD 8H QD JC AH +9C 9H 2D TD QH 2H 5C TC 3D 8H +KC 8S 3D KH 2S TS TC 6S 4D JH +9H 9D QS AC KC 6H 5D 4D 8D AH +9S 5C QS 4H 7C 7D 2H 8S AD JS +3D AC 9S AS 2C 2D 2H 3H JC KH +7H QH KH JD TC KS 5S 8H 4C 8D +2H 7H 3S 2S 5H QS 3C AS 9H KD +AD 3D JD 6H 5S 9C 6D AC 9S 3S +3D 5D 9C 2D AC 4S 2S AD 6C 6S +QC 4C 2D 3H 6S KC QH QD 2H JH +QC 3C 8S 4D 9S 2H 5C 8H QS QD +6D KD 6S 7H 3S KH 2H 5C JC 6C +3S 9S TC 6S 8H 2D AD 7S 8S TS +3C 6H 9C 3H 5C JC 8H QH TD QD +3C JS QD 5D TD 2C KH 9H TH AS +9S TC JD 3D 5C 5H AD QH 9H KC +TC 7H 4H 8H 3H TD 6S AC 7C 2S +QS 9D 5D 3C JC KS 4D 6C JH 2S +9S 6S 3C 7H TS 4C KD 6D 3D 9C +2D 9H AH AC 7H 2S JH 3S 7C QC +QD 9H 3C 2H AC AS 8S KD 8C KH +2D 7S TD TH 6D JD 8D 4D 2H 5S +8S QH KD JD QS JH 4D KC 5H 3S +3C KH QC 6D 8H 3S AH 7D TD 2D +5S 9H QH 4S 6S 6C 6D TS TH 7S +6C 4C 6D QS JS 9C TS 3H 8D 8S +JS 5C 7S AS 2C AH 2H AD 5S TC +KD 6C 9C 9D TS 2S JC 4H 2C QD +QS 9H TC 3H KC KS 4H 3C AD TH +KH 9C 2H KD 9D TC 7S KC JH 2D +7C 3S KC AS 8C 5D 9C 9S QH 3H +2D 8C TD 4C 2H QC 5D TC 2C 7D +KS 4D 6C QH TD KH 5D 7C AD 8D +2S 9S 8S 4C 8C 3D 6H QD 7C 7H +6C 8S QH 5H TS 5C 3C 4S 2S 2H +8S 6S 2H JC 3S 3H 9D 8C 2S 7H +QC 2C 8H 9C AC JD 4C 4H 6S 3S +3H 3S 7D 4C 9S 5H 8H JC 3D TC +QH 2S 2D 9S KD QD 9H AD 6D 9C +8D 2D KS 9S JC 4C JD KC 4S TH +KH TS 6D 4D 5C KD 5H AS 9H AD +QD JS 7C 6D 5D 5C TH 5H QH QS +9D QH KH 5H JH 4C 4D TC TH 6C +KH AS TS 9D KD 9C 7S 4D 8H 5S +KH AS 2S 7D 9D 4C TS TH AH 7C +KS 4D AC 8S 9S 8D TH QH 9D 5C +5D 5C 8C QS TC 4C 3D 3S 2C 8D +9D KS 2D 3C KC 4S 8C KH 6C JC +8H AH 6H 7D 7S QD 3C 4C 6C KC +3H 2C QH 8H AS 7D 4C 8C 4H KC +QD 5S 4H 2C TD AH JH QH 4C 8S +3H QS 5S JS 8H 2S 9H 9C 3S 2C +6H TS 7S JC QD AC TD KC 5S 3H +QH AS QS 7D JC KC 2C 4C 5C 5S +QH 3D AS JS 4H 8D 7H JC 2S 9C +5D 4D 2S 4S 9D 9C 2D QS 8H 7H +6D 7H 3H JS TS AC 2D JH 7C 8S +JH 5H KC 3C TC 5S 9H 4C 8H 9D +8S KC 5H 9H AD KS 9D KH 8D AH +JC 2H 9H KS 6S 3H QC 5H AH 9C +5C KH 5S AD 6C JC 9H QC 9C TD +5S 5D JC QH 2D KS 8H QS 2H TS +JH 5H 5S AH 7H 3C 8S AS TD KH +6H 3D JD 2C 4C KC 7S AH 6C JH +4C KS 9D AD 7S KC 7D 8H 3S 9C +7H 5C 5H 3C 8H QC 3D KH 6D JC +2D 4H 5D 7D QC AD AH 9H QH 8H +KD 8C JS 9D 3S 3C 2H 5D 6D 2S +8S 6S TS 3C 6H 8D 5S 3H TD 6C +KS 3D JH 9C 7C 9S QS 5S 4H 6H +7S 6S TH 4S KC KD 3S JC JH KS +7C 3C 2S 6D QH 2C 7S 5H 8H AH +KC 8D QD 6D KH 5C 7H 9D 3D 9C +6H 2D 8S JS 9S 2S 6D KC 7C TC +KD 9C JH 7H KC 8S 2S 7S 3D 6H +4H 9H 2D 4C 8H 7H 5S 8S 2H 8D +AD 7C 3C 7S 5S 4D 9H 3D JC KH +5D AS 7D 6D 9C JC 4C QH QS KH +KD JD 7D 3D QS QC 8S 6D JS QD +6S 8C 5S QH TH 9H AS AC 2C JD +QC KS QH 7S 3C 4C 5C KC 5D AH +6C 4H 9D AH 2C 3H KD 3D TS 5C +TD 8S QS AS JS 3H KD AC 4H KS +7D 5D TS 9H 4H 4C 9C 2H 8C QC +2C 7D 9H 4D KS 4C QH AD KD JS +QD AD AH KH 9D JS 9H JC KD JD +8S 3C 4S TS 7S 4D 5C 2S 6H 7C +JS 7S 5C KD 6D QH 8S TD 2H 6S +QH 6C TC 6H TD 4C 9D 2H QC 8H +3D TS 4D 2H 6H 6S 2C 7H 8S 6C +9H 9D JD JH 3S AH 2C 6S 3H 8S +2C QS 8C 5S 3H 2S 7D 3C AD 4S +5C QC QH AS TS 4S 6S 4C 5H JS +JH 5C TD 4C 6H JS KD KH QS 4H +TC KH JC 4D 9H 9D 8D KC 3C 8H +2H TC 8S AD 9S 4H TS 7H 2C 5C +4H 2S 6C 5S KS AH 9C 7C 8H KD +TS QH TD QS 3C JH AH 2C 8D 7D +5D KC 3H 5S AC 4S 7H QS 4C 2H +3D 7D QC KH JH 6D 6C TD TH KD +5S 8D TH 6C 9D 7D KH 8C 9S 6D +JD QS 7S QC 2S QH JC 4S KS 8D +7S 5S 9S JD KD 9C JC AD 2D 7C +4S 5H AH JH 9C 5D TD 7C 2D 6S +KC 6C 7H 6S 9C QD 5S 4H KS TD +6S 8D KS 2D TH TD 9H JD TS 3S +KH JS 4H 5D 9D TC TD QC JD TS +QS QD AC AD 4C 6S 2D AS 3H KC +4C 7C 3C TD QS 9C KC AS 8D AD +KC 7H QC 6D 8H 6S 5S AH 7S 8C +3S AD 9H JC 6D JD AS KH 6S JH +AD 3D TS KS 7H JH 2D JS QD AC +9C JD 7C 6D TC 6H 6C JC 3D 3S +QC KC 3S JC KD 2C 8D AH QS TS +AS KD 3D JD 8H 7C 8C 5C QD 6C diff --git a/project_euler/problem_54/sol1.py b/project_euler/problem_54/sol1.py new file mode 100644 index 000000000000..3275fe6cd483 --- /dev/null +++ b/project_euler/problem_54/sol1.py @@ -0,0 +1,358 @@ +""" +Problem: https://projecteuler.net/problem=54 + +In the card game poker, a hand consists of five cards and are ranked, +from lowest to highest, in the following way: + +High Card: Highest value card. +One Pair: Two cards of the same value. +Two Pairs: Two different pairs. +Three of a Kind: Three cards of the same value. +Straight: All cards are consecutive values. +Flush: All cards of the same suit. +Full House: Three of a kind and a pair. +Four of a Kind: Four cards of the same value. +Straight Flush: All cards are consecutive values of same suit. +Royal Flush: Ten, Jack, Queen, King, Ace, in same suit. + +The cards are valued in the order: +2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace. + +If two players have the same ranked hands then the rank made up of the highest +value wins; for example, a pair of eights beats a pair of fives. +But if two ranks tie, for example, both players have a pair of queens, then highest +cards in each hand are compared; if the highest cards tie then the next highest +cards are compared, and so on. + +The file, poker.txt, contains one-thousand random hands dealt to two players. +Each line of the file contains ten cards (separated by a single space): the +first five are Player 1's cards and the last five are Player 2's cards. +You can assume that all hands are valid (no invalid characters or repeated cards), +each player's hand is in no specific order, and in each hand there is a clear winner. + +How many hands does Player 1 win? + +Resources used: +https://en.wikipedia.org/wiki/Texas_hold_%27em +https://en.wikipedia.org/wiki/List_of_poker_hands + +Similar problem on codewars: +https://www.codewars.com/kata/ranking-poker-hands +https://www.codewars.com/kata/sortable-poker-hands +""" +from typing import List, Set, Tuple + + +class PokerHand(object): + """Create an object representing a Poker Hand based on an input of a + string which represents the best 5 card combination from the player's hand + and board cards. + + Attributes: (read-only) + hand: string representing the hand consisting of five cards + + Methods: + compare_with(opponent): takes in player's hand (self) and + opponent's hand (opponent) and compares both hands according to + the rules of Texas Hold'em. + Returns one of 3 strings (Win, Loss, Tie) based on whether + player's hand is better than opponent's hand. + + hand_name(): Returns a string made up of two parts: hand name + and high card. + + Supported operators: + Rich comparison operators: <, >, <=, >=, ==, != + + Supported builtin methods and functions: + list.sort(), sorted() + """ + + _HAND_NAME = [ + "High card", + "One pair", + "Two pairs", + "Three of a kind", + "Straight", + "Flush", + "Full house", + "Four of a kind", + "Straight flush", + "Royal flush", + ] + + _CARD_NAME = [ + "", # placeholder as lists are zero indexed + "One", + "Two", + "Three", + "Four", + "Five", + "Six", + "Seven", + "Eight", + "Nine", + "Ten", + "Jack", + "Queen", + "King", + "Ace", + ] + + def __init__(self, hand: str) -> None: + """ + Initialize hand. + Hand should of type str and should contain only five cards each + separated by a space. + + The cards should be of the following format: + [card value][card suit] + + The first character is the value of the card: + 2, 3, 4, 5, 6, 7, 8, 9, T(en), J(ack), Q(ueen), K(ing), A(ce) + + The second character represents the suit: + S(pades), H(earts), D(iamonds), C(lubs) + + For example: "6S 4C KC AS TH" + """ + if not isinstance(hand, str): + raise TypeError(f"Hand should be of type 'str': {hand!r}") + # split removes duplicate whitespaces so no need of strip + if len(hand.split(" ")) != 5: + raise ValueError(f"Hand should contain only 5 cards: {hand!r}") + self._hand = hand + self._first_pair = 0 + self._second_pair = 0 + self._card_values, self._card_suit = self._internal_state() + self._hand_type = self._get_hand_type() + self._high_card = self._card_values[0] + + @property + def hand(self): + """Returns the self hand""" + return self._hand + + def compare_with(self, other: "PokerHand") -> str: + """ + Determines the outcome of comparing self hand with other hand. + Returns the output as 'Win', 'Loss', 'Tie' according to the rules of + Texas Hold'em. + + Here are some examples: + >>> player = PokerHand("2H 3H 4H 5H 6H") # Stright flush + >>> opponent = PokerHand("KS AS TS QS JS") # Royal flush + >>> player.compare_with(opponent) + 'Loss' + + >>> player = PokerHand("2S AH 2H AS AC") # Full house + >>> opponent = PokerHand("2H 3H 5H 6H 7H") # Flush + >>> player.compare_with(opponent) + 'Win' + + >>> player = PokerHand("2S AH 4H 5S 6C") # High card + >>> opponent = PokerHand("AD 4C 5H 6H 2C") # High card + >>> player.compare_with(opponent) + 'Tie' + """ + # Breaking the tie works on the following order of precedence: + # 1. First pair (default 0) + # 2. Second pair (default 0) + # 3. Compare all cards in reverse order because they are sorted. + + # First pair and second pair will only be a non-zero value if the card + # type is either from the following: + # 21: Four of a kind + # 20: Full house + # 17: Three of a kind + # 16: Two pairs + # 15: One pair + if self._hand_type > other._hand_type: + return "Win" + elif self._hand_type < other._hand_type: + return "Loss" + elif self._first_pair == other._first_pair: + if self._second_pair == other._second_pair: + return self._compare_cards(other) + else: + return "Win" if self._second_pair > other._second_pair else "Loss" + return "Win" if self._first_pair > other._first_pair else "Loss" + + # This function is not part of the problem, I did it just for fun + def hand_name(self) -> str: + """ + Return the name of the hand in the following format: + 'hand name, high card' + + Here are some examples: + >>> PokerHand("KS AS TS QS JS").hand_name() + 'Royal flush' + + >>> PokerHand("2D 6D 3D 4D 5D").hand_name() + 'Straight flush, Six-high' + + >>> PokerHand("JC 6H JS JD JH").hand_name() + 'Four of a kind, Jacks' + + >>> PokerHand("3D 2H 3H 2C 2D").hand_name() + 'Full house, Twos over Threes' + + >>> PokerHand("2H 4D 3C AS 5S").hand_name() # Low ace + 'Straight, Five-high' + + Source: https://en.wikipedia.org/wiki/List_of_poker_hands + """ + name = PokerHand._HAND_NAME[self._hand_type - 14] + high = PokerHand._CARD_NAME[self._high_card] + pair1 = PokerHand._CARD_NAME[self._first_pair] + pair2 = PokerHand._CARD_NAME[self._second_pair] + if self._hand_type in [22, 19, 18]: + return name + f", {high}-high" + elif self._hand_type in [21, 17, 15]: + return name + f", {pair1}s" + elif self._hand_type in [20, 16]: + join = "over" if self._hand_type == 20 else "and" + return name + f", {pair1}s {join} {pair2}s" + elif self._hand_type == 23: + return name + else: + return name + f", {high}" + + def _compare_cards(self, other: "PokerHand") -> str: + # Enumerate gives us the index as well as the element of a list + for index, card_value in enumerate(self._card_values): + if card_value != other._card_values[index]: + return "Win" if card_value > other._card_values[index] else "Loss" + return "Tie" + + def _get_hand_type(self) -> int: + # Number representing the type of hand internally: + # 23: Royal flush + # 22: Straight flush + # 21: Four of a kind + # 20: Full house + # 19: Flush + # 18: Straight + # 17: Three of a kind + # 16: Two pairs + # 15: One pair + # 14: High card + if self._is_flush(): + if self._is_five_high_straight() or self._is_straight(): + return 23 if sum(self._card_values) == 60 else 22 + return 19 + elif self._is_five_high_straight() or self._is_straight(): + return 18 + return 14 + self._is_same_kind() + + def _is_flush(self) -> bool: + return len(self._card_suit) == 1 + + def _is_five_high_straight(self) -> bool: + # If a card is a five high straight (low ace) change the location of + # ace from the start of the list to the end. Check whether the first + # element is ace or not. (Don't want to change again) + # Five high straight (low ace): AH 2H 3S 4C 5D + # Why use sorted here? One call to this function will mutate the list to + # [5, 4, 3, 2, 14] and so for subsequent calls (which will be rare) we + # need to compare the sorted version. + # Refer test_multiple_calls_five_high_straight in test_poker_hand.py + if sorted(self._card_values) == [2, 3, 4, 5, 14]: + if self._card_values[0] == 14: + # Remember, our list is sorted in reverse order + ace_card = self._card_values.pop(0) + self._card_values.append(ace_card) + return True + return False + + def _is_straight(self) -> bool: + for i in range(4): + if self._card_values[i] - self._card_values[i + 1] != 1: + return False + return True + + def _is_same_kind(self) -> int: + # Kind Values for internal use: + # 7: Four of a kind + # 6: Full house + # 3: Three of a kind + # 2: Two pairs + # 1: One pair + # 0: False + kind = val1 = val2 = 0 + for i in range(4): + # Compare two cards at a time, if they are same increase 'kind', + # add the value of the card to val1, if it is repeating again we + # will add 2 to 'kind' as there are now 3 cards with same value. + # If we get card of different value than val1, we will do the same + # thing with val2 + if self._card_values[i] == self._card_values[i + 1]: + if not val1: + val1 = self._card_values[i] + kind += 1 + elif val1 == self._card_values[i]: + kind += 2 + elif not val2: + val2 = self._card_values[i] + kind += 1 + elif val2 == self._card_values[i]: + kind += 2 + # For consistency in hand type (look at note in _get_hand_type function) + kind = kind + 2 if kind in [4, 5] else kind + # first meaning first pair to compare in 'compare_with' + first = max(val1, val2) + second = min(val1, val2) + # If it's full house (three count pair + two count pair), make sure + # first pair is three count and if not then switch them both. + if kind == 6 and self._card_values.count(first) != 3: + first, second = second, first + self._first_pair = first + self._second_pair = second + return kind + + def _internal_state(self) -> Tuple[List[int], Set[str]]: + # Internal representation of hand as a list of card values and + # a set of card suit + trans: dict = {"T": "10", "J": "11", "Q": "12", "K": "13", "A": "14"} + new_hand = self._hand.translate(str.maketrans(trans)).split() + card_values = [int(card[:-1]) for card in new_hand] + card_suit = {card[-1] for card in new_hand} + return sorted(card_values, reverse=True), card_suit + + def __repr__(self): + return f'{self.__class__}("{self._hand}")' + + def __str__(self): + return self._hand + + # Rich comparison operators (used in list.sort() and sorted() builtin functions) + # Note that this is not part of the problem but another extra feature where + # if you have a list of PokerHand objects, you can sort them just through + # the builtin functions. + def __eq__(self, other): + if isinstance(other, PokerHand): + return self.compare_with(other) == "Tie" + return NotImplemented + + def __lt__(self, other): + if isinstance(other, PokerHand): + return self.compare_with(other) == "Loss" + return NotImplemented + + def __le__(self, other): + if isinstance(other, PokerHand): + return self < other or self == other + return NotImplemented + + def __gt__(self, other): + if isinstance(other, PokerHand): + return not self < other and self != other + return NotImplemented + + def __ge__(self, other): + if isinstance(other, PokerHand): + return not self < other + return NotImplemented + + def __hash__(self): + return object.__hash__(self) diff --git a/project_euler/problem_54/test_poker_hand.py b/project_euler/problem_54/test_poker_hand.py new file mode 100644 index 000000000000..f60c3aba6616 --- /dev/null +++ b/project_euler/problem_54/test_poker_hand.py @@ -0,0 +1,228 @@ +import os +from itertools import chain +from random import randrange, shuffle + +import pytest + +from .sol1 import PokerHand + +SORTED_HANDS = ( + "4S 3H 2C 7S 5H", + "9D 8H 2C 6S 7H", + "2D 6D 9D TH 7D", + "TC 8C 2S JH 6C", + "JH 8S TH AH QH", + "TS KS 5S 9S AC", + "KD 6S 9D TH AD", + "KS 8D 4D 9S 4S", # pair + "8C 4S KH JS 4D", # pair + "QH 8H KD JH 8S", # pair + "KC 4H KS 2H 8D", # pair + "KD 4S KC 3H 8S", # pair + "AH 8S AS KC JH", # pair + "3H 4C 4H 3S 2H", # 2 pairs + "5S 5D 2C KH KH", # 2 pairs + "3C KH 5D 5S KH", # 2 pairs + "AS 3C KH AD KH", # 2 pairs + "7C 7S 3S 7H 5S", # 3 of a kind + "7C 7S KH 2H 7H", # 3 of a kind + "AC KH QH AH AS", # 3 of a kind + "2H 4D 3C AS 5S", # straight (low ace) + "3C 5C 4C 2C 6H", # straight + "6S 8S 7S 5H 9H", # straight + "JS QS 9H TS KH", # straight + "QC KH TS JS AH", # straight (high ace) + "8C 9C 5C 3C TC", # flush + "3S 8S 9S 5S KS", # flush + "4C 5C 9C 8C KC", # flush + "JH 8H AH KH QH", # flush + "3D 2H 3H 2C 2D", # full house + "2H 2C 3S 3H 3D", # full house + "KH KC 3S 3H 3D", # full house + "JC 6H JS JD JH", # 4 of a kind + "JC 7H JS JD JH", # 4 of a kind + "JC KH JS JD JH", # 4 of a kind + "2S AS 4S 5S 3S", # straight flush (low ace) + "2D 6D 3D 4D 5D", # straight flush + "5C 6C 3C 7C 4C", # straight flush + "JH 9H TH KH QH", # straight flush + "JH AH TH KH QH", # royal flush (high ace straight flush) +) + +TEST_COMPARE = ( + ("2H 3H 4H 5H 6H", "KS AS TS QS JS", "Loss"), + ("2H 3H 4H 5H 6H", "AS AD AC AH JD", "Win"), + ("AS AH 2H AD AC", "JS JD JC JH 3D", "Win"), + ("2S AH 2H AS AC", "JS JD JC JH AD", "Loss"), + ("2S AH 2H AS AC", "2H 3H 5H 6H 7H", "Win"), + ("AS 3S 4S 8S 2S", "2H 3H 5H 6H 7H", "Win"), + ("2H 3H 5H 6H 7H", "2S 3H 4H 5S 6C", "Win"), + ("2S 3H 4H 5S 6C", "3D 4C 5H 6H 2S", "Tie"), + ("2S 3H 4H 5S 6C", "AH AC 5H 6H AS", "Win"), + ("2S 2H 4H 5S 4C", "AH AC 5H 6H AS", "Loss"), + ("2S 2H 4H 5S 4C", "AH AC 5H 6H 7S", "Win"), + ("6S AD 7H 4S AS", "AH AC 5H 6H 7S", "Loss"), + ("2S AH 4H 5S KC", "AH AC 5H 6H 7S", "Loss"), + ("2S 3H 6H 7S 9C", "7H 3C TH 6H 9S", "Loss"), + ("4S 5H 6H TS AC", "3S 5H 6H TS AC", "Win"), + ("2S AH 4H 5S 6C", "AD 4C 5H 6H 2C", "Tie"), + ("AS AH 3H AD AC", "AS AH 2H AD AC", "Win"), + ("AH AC 5H 5C QS", "AH AC 5H 5C KS", "Loss"), + ("AH AC 5H 5C QS", "KH KC 5H 5C QS", "Win"), + ("7C 7S KH 2H 7H", "3C 3S AH 2H 3H", "Win"), + ("3C 3S AH 2H 3H", "7C 7S KH 2H 7H", "Loss"), + ("6H 5H 4H 3H 2H", "5H 4H 3H 2H AH", "Win"), + ("5H 4H 3H 2H AH", "5H 4H 3H 2H AH", "Tie"), + ("5H 4H 3H 2H AH", "6H 5H 4H 3H 2H", "Loss"), + ("AH AD KS KC AC", "AH KD KH AC KC", "Win"), + ("2H 4D 3C AS 5S", "2H 4D 3C 6S 5S", "Loss"), + ("2H 3S 3C 3H 2S", "3S 3C 2S 2H 2D", "Win"), + ("4D 6D 5D 2D JH", "3S 8S 3H TC KH", "Loss"), + ("4S 6C 8S 3S 7S", "AD KS 2D 7D 7C", "Loss"), + ("6S 4C 7H 8C 3H", "5H JC AH 9D 9C", "Loss"), + ("9D 9H JH TC QH", "3C 2S JS 5C 7H", "Win"), + ("2H TC 8S AD 9S", "4H TS 7H 2C 5C", "Win"), + ("9D 3S 2C 7S 7C", "JC TD 3C TC 9H", "Loss"), +) + +TEST_FLUSH = ( + ("2H 3H 4H 5H 6H", True), + ("AS AH 2H AD AC", False), + ("2H 3H 5H 6H 7H", True), + ("KS AS TS QS JS", True), + ("8H 9H QS JS TH", False), + ("AS 3S 4S 8S 2S", True), +) + +TEST_STRAIGHT = ( + ("2H 3H 4H 5H 6H", True), + ("AS AH 2H AD AC", False), + ("2H 3H 5H 6H 7H", False), + ("KS AS TS QS JS", True), + ("8H 9H QS JS TH", True), +) + +TEST_FIVE_HIGH_STRAIGHT = ( + ("2H 4D 3C AS 5S", True, [5, 4, 3, 2, 14]), + ("2H 5D 3C AS 5S", False, [14, 5, 5, 3, 2]), + ("JH QD KC AS TS", False, [14, 13, 12, 11, 10]), + ("9D 3S 2C 7S 7C", False, [9, 7, 7, 3, 2]), +) + +TEST_KIND = ( + ("JH AH TH KH QH", 0), + ("JH 9H TH KH QH", 0), + ("JC KH JS JD JH", 7), + ("KH KC 3S 3H 3D", 6), + ("8C 9C 5C 3C TC", 0), + ("JS QS 9H TS KH", 0), + ("7C 7S KH 2H 7H", 3), + ("3C KH 5D 5S KH", 2), + ("QH 8H KD JH 8S", 1), + ("2D 6D 9D TH 7D", 0), +) + +TEST_TYPES = ( + ("JH AH TH KH QH", 23), + ("JH 9H TH KH QH", 22), + ("JC KH JS JD JH", 21), + ("KH KC 3S 3H 3D", 20), + ("8C 9C 5C 3C TC", 19), + ("JS QS 9H TS KH", 18), + ("7C 7S KH 2H 7H", 17), + ("3C KH 5D 5S KH", 16), + ("QH 8H KD JH 8S", 15), + ("2D 6D 9D TH 7D", 14), +) + + +def generate_random_hand(): + play, oppo = randrange(len(SORTED_HANDS)), randrange(len(SORTED_HANDS)) + expected = ["Loss", "Tie", "Win"][(play >= oppo) + (play > oppo)] + hand, other = SORTED_HANDS[play], SORTED_HANDS[oppo] + return hand, other, expected + + +def generate_random_hands(number_of_hands: int = 100): + return (generate_random_hand() for _ in range(number_of_hands)) + + +@pytest.mark.parametrize("hand, expected", TEST_FLUSH) +def test_hand_is_flush(hand, expected): + assert PokerHand(hand)._is_flush() == expected + + +@pytest.mark.parametrize("hand, expected", TEST_STRAIGHT) +def test_hand_is_straight(hand, expected): + assert PokerHand(hand)._is_straight() == expected + + +@pytest.mark.parametrize("hand, expected, card_values", TEST_FIVE_HIGH_STRAIGHT) +def test_hand_is_five_high_straight(hand, expected, card_values): + player = PokerHand(hand) + assert player._is_five_high_straight() == expected + assert player._card_values == card_values + + +@pytest.mark.parametrize("hand, expected", TEST_KIND) +def test_hand_is_same_kind(hand, expected): + assert PokerHand(hand)._is_same_kind() == expected + + +@pytest.mark.parametrize("hand, expected", TEST_TYPES) +def test_hand_values(hand, expected): + assert PokerHand(hand)._hand_type == expected + + +@pytest.mark.parametrize("hand, other, expected", TEST_COMPARE) +def test_compare_simple(hand, other, expected): + assert PokerHand(hand).compare_with(PokerHand(other)) == expected + + +@pytest.mark.parametrize("hand, other, expected", generate_random_hands()) +def test_compare_random(hand, other, expected): + assert PokerHand(hand).compare_with(PokerHand(other)) == expected + + +def test_hand_sorted(): + POKER_HANDS = [PokerHand(hand) for hand in SORTED_HANDS] + list_copy = POKER_HANDS.copy() + shuffle(list_copy) + user_sorted = chain(sorted(list_copy)) + for index, hand in enumerate(user_sorted): + assert hand == POKER_HANDS[index] + + +def test_custom_sort_five_high_straight(): + # Test that five high straights are compared correctly. + pokerhands = [PokerHand("2D AC 3H 4H 5S"), PokerHand("2S 3H 4H 5S 6C")] + pokerhands.sort(reverse=True) + assert pokerhands[0].__str__() == "2S 3H 4H 5S 6C" + + +def test_multiple_calls_five_high_straight(): + # Multiple calls to five_high_straight function should still return True + # and shouldn't mutate the list in every call other than the first. + pokerhand = PokerHand("2C 4S AS 3D 5C") + expected = True + expected_card_values = [5, 4, 3, 2, 14] + for _ in range(10): + assert pokerhand._is_five_high_straight() == expected + assert pokerhand._card_values == expected_card_values + + +def test_euler_project(): + # Problem number 54 from Project Euler + # Testing from poker_hands.txt file + answer = 0 + script_dir = os.path.abspath(os.path.dirname(__file__)) + poker_hands = os.path.join(script_dir, "poker_hands.txt") + with open(poker_hands, "r") as file_hand: + for line in file_hand: + player_hand = line[:14].strip() + opponent_hand = line[15:].strip() + player, opponent = PokerHand(player_hand), PokerHand(opponent_hand) + output = player.compare_with(opponent) + if output == "Win": + answer += 1 + assert answer == 376 From 718be54dbb430f647c439b39f9d5b4f09b62ccde Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Mon, 21 Sep 2020 01:03:26 +0530 Subject: [PATCH 39/55] Update sol1.py (#2455) --- project_euler/problem_48/sol1.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/project_euler/problem_48/sol1.py b/project_euler/problem_48/sol1.py index 06ad1408dcef..01ff702d9cd5 100644 --- a/project_euler/problem_48/sol1.py +++ b/project_euler/problem_48/sol1.py @@ -2,14 +2,15 @@ Self Powers Problem 48 -The series, 11 + 22 + 33 + ... + 1010 = 10405071317. +The series, 1^1 + 2^2 + 3^3 + ... + 10^10 = 10405071317. -Find the last ten digits of the series, 11 + 22 + 33 + ... + 10001000. +Find the last ten digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000. """ def solution(): - """Returns the last 10 digits of the series, 11 + 22 + 33 + ... + 10001000. + """ + Returns the last 10 digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000. >>> solution() '9110846700' From a1ea76bcf3f4da8348cd483f8062690ddf279997 Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Tue, 22 Sep 2020 21:15:11 +0800 Subject: [PATCH 40/55] Optimization problem_10 in project_euler (#2453) * optimization for problem09 in project_euler * added benchmark code * fixup! Format Python code with psf/black push * Update project_euler/problem_09/sol1.py Co-authored-by: Christian Clauss * updating DIRECTORY.md * Update project_euler/problem_09/sol1.py * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Christian Clauss --- DIRECTORY.md | 1 + project_euler/problem_09/sol1.py | 39 +++++++++++++++++-- project_euler/problem_09/sol3.py | 5 +-- .../can_string_be_rearranged_as_palindrome.py | 4 +- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index d91d34803a1c..03044e01084b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -713,6 +713,7 @@ ## Strings * [Aho Corasick](https://github.com/TheAlgorithms/Python/blob/master/strings/aho_corasick.py) * [Boyer Moore Search](https://github.com/TheAlgorithms/Python/blob/master/strings/boyer_moore_search.py) + * [Can String Be Rearranged As Palindrome](https://github.com/TheAlgorithms/Python/blob/master/strings/can_string_be_rearranged_as_palindrome.py) * [Capitalize](https://github.com/TheAlgorithms/Python/blob/master/strings/capitalize.py) * [Check Anagrams](https://github.com/TheAlgorithms/Python/blob/master/strings/check_anagrams.py) * [Check Pangram](https://github.com/TheAlgorithms/Python/blob/master/strings/check_pangram.py) diff --git a/project_euler/problem_09/sol1.py b/project_euler/problem_09/sol1.py index 3bb5c968115d..caba6b1b1530 100644 --- a/project_euler/problem_09/sol1.py +++ b/project_euler/problem_09/sol1.py @@ -16,7 +16,6 @@ def solution(): 1. a < b < c 2. a**2 + b**2 = c**2 3. a + b + c = 1000 - # The code below has been commented due to slow execution affecting Travis. # >>> solution() # 31875000 @@ -30,6 +29,40 @@ def solution(): return a * b * c +def solution_fast(): + """ + Returns the product of a,b,c which are Pythagorean Triplet that satisfies + the following: + 1. a < b < c + 2. a**2 + b**2 = c**2 + 3. a + b + c = 1000 + + # The code below has been commented due to slow execution affecting Travis. + # >>> solution_fast() + # 31875000 + """ + for a in range(300): + for b in range(400): + c = 1000 - a - b + if a < b < c and (a ** 2) + (b ** 2) == (c ** 2): + return a * b * c + + +def benchmark() -> None: + """ + Benchmark code comparing two different version function. + """ + import timeit + + print( + timeit.timeit("solution()", setup="from __main__ import solution", number=1000) + ) + print( + timeit.timeit( + "solution_fast()", setup="from __main__ import solution_fast", number=1000 + ) + ) + + if __name__ == "__main__": - print("Please Wait...") - print(solution()) + benchmark() diff --git a/project_euler/problem_09/sol3.py b/project_euler/problem_09/sol3.py index a6df46a3a66b..ed27f089bd40 100644 --- a/project_euler/problem_09/sol3.py +++ b/project_euler/problem_09/sol3.py @@ -25,11 +25,10 @@ def solution(): # 31875000 """ return [ - a * b * c + a * b * (1000 - a - b) for a in range(1, 999) for b in range(a, 999) - for c in range(b, 999) - if (a * a + b * b == c * c) and (a + b + c == 1000) + if (a * a + b * b == (1000 - a - b) ** 2) ][0] diff --git a/strings/can_string_be_rearranged_as_palindrome.py b/strings/can_string_be_rearranged_as_palindrome.py index 92bc3b95b243..7fedc5877e26 100644 --- a/strings/can_string_be_rearranged_as_palindrome.py +++ b/strings/can_string_be_rearranged_as_palindrome.py @@ -8,7 +8,9 @@ # Counter is faster for long strings and non-Counter is faster for short strings. -def can_string_be_rearranged_as_palindrome_counter(input_str: str = "",) -> bool: +def can_string_be_rearranged_as_palindrome_counter( + input_str: str = "", +) -> bool: """ A Palindrome is a String that reads the same forward as it does backwards. Examples of Palindromes mom, dad, malayalam From 6e6a49d19f918c09648199d5cab7d2c04fcb6a5e Mon Sep 17 00:00:00 2001 From: Dhruv Date: Wed, 23 Sep 2020 16:54:32 +0530 Subject: [PATCH 41/55] Config Travis CI for two jobs (#2463) * Testing Travis CI configuration for project Euler * Fix: Installing mypy and pytest-cov for testing * Remove unnecessary checks for project_euler job * Removing branches section * Update .travis.yml * Update .travis.yml * Update .travis.yml * Update .travis.yml Co-authored-by: Christian Clauss --- .travis.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index a03f8161f13e..cbbdc25e04d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,16 +5,23 @@ python: 3.8 cache: pip before_install: pip install --upgrade pip setuptools six install: pip install black flake8 +jobs: + include: + - name: Build + before_script: + - black --check . || true + - flake8 --ignore=E203,W503 --max-complexity=25 --max-line-length=88 --statistics --count . + - scripts/validate_filenames.py # no uppercase, no spaces, in a directory + - pip install -r requirements.txt # fast fail on black, flake8, validate_filenames + script: + - mypy --ignore-missing-imports . + - pytest --doctest-modules --ignore=project_euler/ --durations=10 --cov-report=term-missing:skip-covered --cov=. . + - name: Project Euler + before_script: pip install pytest-cov + script: + - pytest --doctest-modules --durations=10 --cov-report=term-missing:skip-covered --cov=project_euler/ project_euler/ notifications: webhooks: https://www.travisbuddy.com/ on_success: never -before_script: - - black --check . || true - - flake8 --ignore=E203,W503 --max-complexity=25 --max-line-length=88 --statistics --count . - - scripts/validate_filenames.py # no uppercase, no spaces, in a directory - - pip install -r requirements.txt # fast fail on black, flake8, validate_filenames -script: - - mypy --ignore-missing-imports . - - pytest --doctest-modules --durations=10 --cov-report=term-missing:skip-covered --cov=. . after_success: - scripts/build_directory_md.py 2>&1 | tee DIRECTORY.md From 9200a2e54362ecd6be6cfc7e257a37e7a4f16013 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 23 Sep 2020 13:30:13 +0200 Subject: [PATCH 42/55] from __future__ import annotations (#2464) * from __future__ import annotations * fixup! from __future__ import annotations * fixup! from __future__ import annotations * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- .travis.yml | 6 ++--- arithmetic_analysis/in_static_equilibrium.py | 4 +-- backtracking/coloring.py | 8 +++--- backtracking/hamiltonian_cycle.py | 8 +++--- backtracking/knight_tour.py | 10 +++---- backtracking/n_queens_math.py | 10 +++---- cellular_automata/one_dimensional.py | 8 +++--- ciphers/rsa_factorization.py | 5 ++-- compression/burrows_wheeler.py | 6 ++--- .../binary_tree/lazy_segment_tree.py | 5 ++-- .../binary_tree/lowest_common_ancestor.py | 19 +++++++------- .../binary_tree/non_recursive_segment_tree.py | 6 +++-- data_structures/binary_tree/treap.py | 5 ++-- data_structures/linked_list/skip_list.py | 8 +++--- .../strassen_matrix_multiplication.py | 21 +++++++-------- dynamic_programming/fast_fibonacci.py | 5 ++-- dynamic_programming/fractional_knapsack_2.py | 6 ++--- .../iterating_through_submasks.py | 4 +-- .../longest_increasing_subsequence.py | 4 +-- ...longest_increasing_subsequence_o(nlogn).py | 4 +-- dynamic_programming/max_non_adjacent_sum.py | 4 +-- dynamic_programming/max_sub_array.py | 4 +-- dynamic_programming/minimum_cost_path.py | 4 +-- genetic_algorithm/basic_string.py | 13 +++++----- graphics/bezier_curve.py | 14 +++++----- graphs/bellman_ford.py | 4 +-- graphs/bidirectional_a_star.py | 13 +++++----- graphs/bidirectional_breadth_first_search.py | 13 +++++----- graphs/breadth_first_search_2.py | 4 +-- graphs/breadth_first_search_shortest_path.py | 4 +-- graphs/depth_first_search.py | 4 +-- graphs/gale_shapley_bigraph.py | 4 +-- graphs/greedy_best_first.py | 8 +++--- graphs/karger.py | 9 +++---- graphs/prim.py | 2 +- linear_algebra/src/polynom_for_points.py | 12 ++++----- linear_algebra/src/transformations_2d.py | 11 ++++---- maths/3n_plus_1.py | 4 +-- maths/abs_max.py | 4 +-- maths/allocation_number.py | 4 +-- maths/collatz_sequence.py | 4 +-- maths/entropy.py | 4 +-- maths/is_square_free.py | 4 +-- maths/line_length.py | 8 +++--- maths/monte_carlo_dice.py | 7 ++--- maths/prime_factors.py | 4 +-- maths/quadratic_equations_complex_numbers.py | 5 ++-- maths/relu.py | 4 +-- matrix/inverse_of_matrix.py | 5 ++-- matrix/matrix_operation.py | 26 +++++++++---------- matrix/searching_in_sorted_matrix.py | 22 +++++++++------- other/dijkstra_bankers_algorithm.py | 17 ++++++------ other/markov_chain.py | 9 ++++--- other/triplet_sum.py | 11 ++++---- project_euler/problem_35/sol1.py | 4 +-- project_euler/problem_37/sol1.py | 7 +++-- project_euler/problem_39/sol1.py | 5 ++-- project_euler/problem_41/sol1.py | 5 ++-- project_euler/problem_46/sol1.py | 4 +-- project_euler/problem_54/sol1.py | 4 +-- scheduling/first_come_first_served.py | 12 ++++----- scheduling/round_robin.py | 9 ++++--- scheduling/shortest_job_first.py | 12 ++++----- searches/double_linear_search.py | 4 +-- searches/simple_binary_search.py | 4 +-- sorts/iterative_merge_sort.py | 6 ++--- sorts/merge_insertion_sort.py | 4 +-- sorts/radix_sort.py | 4 +-- sorts/recursive_insertion_sort.py | 6 ++--- traversals/binary_tree_traversals.py | 3 ++- web_programming/fetch_jobs.py | 6 +++-- .../get_imdb_top_250_movies_csv.py | 5 ++-- 72 files changed, 275 insertions(+), 250 deletions(-) diff --git a/.travis.yml b/.travis.yml index cbbdc25e04d8..d2394b4097f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,14 +14,14 @@ jobs: - scripts/validate_filenames.py # no uppercase, no spaces, in a directory - pip install -r requirements.txt # fast fail on black, flake8, validate_filenames script: - - mypy --ignore-missing-imports . + - mypy --ignore-missing-imports . || true # https://github.com/python/mypy/issues/7907 - pytest --doctest-modules --ignore=project_euler/ --durations=10 --cov-report=term-missing:skip-covered --cov=. . - name: Project Euler before_script: pip install pytest-cov script: - pytest --doctest-modules --durations=10 --cov-report=term-missing:skip-covered --cov=project_euler/ project_euler/ +after_success: + - scripts/build_directory_md.py 2>&1 | tee DIRECTORY.md notifications: webhooks: https://www.travisbuddy.com/ on_success: never -after_success: - - scripts/build_directory_md.py 2>&1 | tee DIRECTORY.md diff --git a/arithmetic_analysis/in_static_equilibrium.py b/arithmetic_analysis/in_static_equilibrium.py index dd7fa706143e..f08b39c3505c 100644 --- a/arithmetic_analysis/in_static_equilibrium.py +++ b/arithmetic_analysis/in_static_equilibrium.py @@ -6,14 +6,14 @@ mypy : passed """ -from typing import List +from __future__ import annotations from numpy import array, cos, cross, radians, sin # type: ignore def polar_force( magnitude: float, angle: float, radian_mode: bool = False -) -> List[float]: +) -> list[float]: """ Resolves force along rectangular components. (force, angle) => (force_x, force_y) diff --git a/backtracking/coloring.py b/backtracking/coloring.py index 3956b21a9182..ceaffe3fae76 100644 --- a/backtracking/coloring.py +++ b/backtracking/coloring.py @@ -5,11 +5,11 @@ Wikipedia: https://en.wikipedia.org/wiki/Graph_coloring """ -from typing import List +from __future__ import annotations def valid_coloring( - neighbours: List[int], colored_vertices: List[int], color: int + neighbours: list[int], colored_vertices: list[int], color: int ) -> bool: """ For each neighbour check if coloring constraint is satisfied @@ -35,7 +35,7 @@ def valid_coloring( def util_color( - graph: List[List[int]], max_colors: int, colored_vertices: List[int], index: int + graph: list[list[int]], max_colors: int, colored_vertices: list[int], index: int ) -> bool: """ Pseudo-Code @@ -86,7 +86,7 @@ def util_color( return False -def color(graph: List[List[int]], max_colors: int) -> List[int]: +def color(graph: list[list[int]], max_colors: int) -> list[int]: """ Wrapper function to call subroutine called util_color which will either return True or False. diff --git a/backtracking/hamiltonian_cycle.py b/backtracking/hamiltonian_cycle.py index 7be1ea350d7c..bf15cce4aca4 100644 --- a/backtracking/hamiltonian_cycle.py +++ b/backtracking/hamiltonian_cycle.py @@ -6,11 +6,11 @@ Wikipedia: https://en.wikipedia.org/wiki/Hamiltonian_path """ -from typing import List +from __future__ import annotations def valid_connection( - graph: List[List[int]], next_ver: int, curr_ind: int, path: List[int] + graph: list[list[int]], next_ver: int, curr_ind: int, path: list[int] ) -> bool: """ Checks whether it is possible to add next into path by validating 2 statements @@ -47,7 +47,7 @@ def valid_connection( return not any(vertex == next_ver for vertex in path) -def util_hamilton_cycle(graph: List[List[int]], path: List[int], curr_ind: int) -> bool: +def util_hamilton_cycle(graph: list[list[int]], path: list[int], curr_ind: int) -> bool: """ Pseudo-Code Base Case: @@ -108,7 +108,7 @@ def util_hamilton_cycle(graph: List[List[int]], path: List[int], curr_ind: int) return False -def hamilton_cycle(graph: List[List[int]], start_index: int = 0) -> List[int]: +def hamilton_cycle(graph: list[list[int]], start_index: int = 0) -> list[int]: r""" Wrapper function to call subroutine called util_hamilton_cycle, which will either return array of vertices indicating hamiltonian cycle diff --git a/backtracking/knight_tour.py b/backtracking/knight_tour.py index e4a93fbc2105..2413ba468838 100644 --- a/backtracking/knight_tour.py +++ b/backtracking/knight_tour.py @@ -1,9 +1,9 @@ # Knight Tour Intro: https://www.youtube.com/watch?v=ab_dY3dZFHM -from typing import List, Tuple +from __future__ import annotations -def get_valid_pos(position: Tuple[int], n: int) -> List[Tuple[int]]: +def get_valid_pos(position: tuple[int], n: int) -> list[tuple[int]]: """ Find all the valid positions a knight can move to from the current position. @@ -32,7 +32,7 @@ def get_valid_pos(position: Tuple[int], n: int) -> List[Tuple[int]]: return permissible_positions -def is_complete(board: List[List[int]]) -> bool: +def is_complete(board: list[list[int]]) -> bool: """ Check if the board (matrix) has been completely filled with non-zero values. @@ -46,7 +46,7 @@ def is_complete(board: List[List[int]]) -> bool: return not any(elem == 0 for row in board for elem in row) -def open_knight_tour_helper(board: List[List[int]], pos: Tuple[int], curr: int) -> bool: +def open_knight_tour_helper(board: list[list[int]], pos: tuple[int], curr: int) -> bool: """ Helper function to solve knight tour problem. """ @@ -66,7 +66,7 @@ def open_knight_tour_helper(board: List[List[int]], pos: Tuple[int], curr: int) return False -def open_knight_tour(n: int) -> List[List[int]]: +def open_knight_tour(n: int) -> list[list[int]]: """ Find the solution for the knight tour problem for a board of size n. Raises ValueError if the tour cannot be performed for the given size. diff --git a/backtracking/n_queens_math.py b/backtracking/n_queens_math.py index fb2b74bd7c4a..811611971616 100644 --- a/backtracking/n_queens_math.py +++ b/backtracking/n_queens_math.py @@ -75,14 +75,14 @@ for another one or vice versa. """ -from typing import List +from __future__ import annotations def depth_first_search( - possible_board: List[int], - diagonal_right_collisions: List[int], - diagonal_left_collisions: List[int], - boards: List[List[str]], + possible_board: list[int], + diagonal_right_collisions: list[int], + diagonal_left_collisions: list[int], + boards: list[list[str]], n: int, ) -> None: """ diff --git a/cellular_automata/one_dimensional.py b/cellular_automata/one_dimensional.py index a6229dd9096f..da77e444502f 100644 --- a/cellular_automata/one_dimensional.py +++ b/cellular_automata/one_dimensional.py @@ -4,7 +4,7 @@ https://mathworld.wolfram.com/ElementaryCellularAutomaton.html """ -from typing import List +from __future__ import annotations from PIL import Image @@ -15,7 +15,7 @@ # fmt: on -def format_ruleset(ruleset: int) -> List[int]: +def format_ruleset(ruleset: int) -> list[int]: """ >>> format_ruleset(11100) [0, 0, 0, 1, 1, 1, 0, 0] @@ -27,7 +27,7 @@ def format_ruleset(ruleset: int) -> List[int]: return [int(c) for c in f"{ruleset:08}"[:8]] -def new_generation(cells: List[List[int]], rule: List[int], time: int) -> List[int]: +def new_generation(cells: list[list[int]], rule: list[int], time: int) -> list[int]: population = len(cells[0]) # 31 next_generation = [] for i in range(population): @@ -41,7 +41,7 @@ def new_generation(cells: List[List[int]], rule: List[int], time: int) -> List[i return next_generation -def generate_image(cells: List[List[int]]) -> Image.Image: +def generate_image(cells: list[list[int]]) -> Image.Image: """ Convert the cells into a greyscale PIL.Image.Image and return it to the caller. >>> from random import random diff --git a/ciphers/rsa_factorization.py b/ciphers/rsa_factorization.py index 9ec34e6c5a17..6df32b6cc887 100644 --- a/ciphers/rsa_factorization.py +++ b/ciphers/rsa_factorization.py @@ -7,12 +7,13 @@ More readable source: https://www.di-mgt.com.au/rsa_factorize_n.html large number can take minutes to factor, therefore are not included in doctest. """ +from __future__ import annotations + import math import random -from typing import List -def rsafactor(d: int, e: int, N: int) -> List[int]: +def rsafactor(d: int, e: int, N: int) -> list[int]: """ This function returns the factors of N, where p*q=N Return: [p, q] diff --git a/compression/burrows_wheeler.py b/compression/burrows_wheeler.py index 03912f80e1a7..1a6610915e65 100644 --- a/compression/burrows_wheeler.py +++ b/compression/burrows_wheeler.py @@ -10,10 +10,10 @@ original character. The BWT is thus a "free" method of improving the efficiency of text compression algorithms, costing only some extra computation. """ -from typing import Dict, List +from __future__ import annotations -def all_rotations(s: str) -> List[str]: +def all_rotations(s: str) -> list[str]: """ :param s: The string that will be rotated len(s) times. :return: A list with the rotations. @@ -43,7 +43,7 @@ def all_rotations(s: str) -> List[str]: return [s[i:] + s[:i] for i in range(len(s))] -def bwt_transform(s: str) -> Dict: +def bwt_transform(s: str) -> dict: """ :param s: The string that will be used at bwt algorithm :return: the string composed of the last char of each row of the ordered diff --git a/data_structures/binary_tree/lazy_segment_tree.py b/data_structures/binary_tree/lazy_segment_tree.py index 38d93a32e767..5bc79e74efcd 100644 --- a/data_structures/binary_tree/lazy_segment_tree.py +++ b/data_structures/binary_tree/lazy_segment_tree.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import math -from typing import List class SegmentTree: @@ -36,7 +37,7 @@ def right(self, idx: int) -> int: return idx * 2 + 1 def build( - self, idx: int, left_element: int, right_element: int, A: List[int] + self, idx: int, left_element: int, right_element: int, A: list[int] ) -> None: if left_element == right_element: self.segment_tree[idx] = A[left_element - 1] diff --git a/data_structures/binary_tree/lowest_common_ancestor.py b/data_structures/binary_tree/lowest_common_ancestor.py index c25536cdaef0..2f1e893fcf99 100644 --- a/data_structures/binary_tree/lowest_common_ancestor.py +++ b/data_structures/binary_tree/lowest_common_ancestor.py @@ -1,11 +1,12 @@ # https://en.wikipedia.org/wiki/Lowest_common_ancestor # https://en.wikipedia.org/wiki/Breadth-first_search +from __future__ import annotations + import queue -from typing import Dict, List, Tuple -def swap(a: int, b: int) -> Tuple[int, int]: +def swap(a: int, b: int) -> tuple[int, int]: """ Return a tuple (b, a) when given two integers a and b >>> swap(2,3) @@ -21,7 +22,7 @@ def swap(a: int, b: int) -> Tuple[int, int]: return a, b -def create_sparse(max_node: int, parent: List[List[int]]) -> List[List[int]]: +def create_sparse(max_node: int, parent: list[list[int]]) -> list[list[int]]: """ creating sparse table which saves each nodes 2^i-th parent """ @@ -35,8 +36,8 @@ def create_sparse(max_node: int, parent: List[List[int]]) -> List[List[int]]: # returns lca of node u,v def lowest_common_ancestor( - u: int, v: int, level: List[int], parent: List[List[int]] -) -> List[List[int]]: + u: int, v: int, level: list[int], parent: list[list[int]] +) -> list[list[int]]: # u must be deeper in the tree than v if level[u] < level[v]: u, v = swap(u, v) @@ -57,12 +58,12 @@ def lowest_common_ancestor( # runs a breadth first search from root node of the tree def breadth_first_search( - level: List[int], - parent: List[List[int]], + level: list[int], + parent: list[list[int]], max_node: int, - graph: Dict[int, int], + graph: dict[int, int], root=1, -) -> Tuple[List[int], List[List[int]]]: +) -> tuple[list[int], list[list[int]]]: """ sets every nodes direct parent parent of root node is set to 0 diff --git a/data_structures/binary_tree/non_recursive_segment_tree.py b/data_structures/binary_tree/non_recursive_segment_tree.py index cdcf1fa8dd2d..064e5aded7b4 100644 --- a/data_structures/binary_tree/non_recursive_segment_tree.py +++ b/data_structures/binary_tree/non_recursive_segment_tree.py @@ -35,13 +35,15 @@ >>> st.query(0, 2) [1, 2, 3] """ -from typing import Callable, List, TypeVar +from __future__ import annotations + +from typing import Callable, TypeVar T = TypeVar("T") class SegmentTree: - def __init__(self, arr: List[T], fnc: Callable[[T, T], T]) -> None: + def __init__(self, arr: list[T], fnc: Callable[[T, T], T]) -> None: """ Segment Tree constructor, it works just with commutative combiner. :param arr: list of elements for the segment tree diff --git a/data_structures/binary_tree/treap.py b/data_structures/binary_tree/treap.py index fbb57650280e..26648f7aba61 100644 --- a/data_structures/binary_tree/treap.py +++ b/data_structures/binary_tree/treap.py @@ -1,7 +1,8 @@ # flake8: noqa +from __future__ import annotations + from random import random -from typing import Tuple class Node: @@ -33,7 +34,7 @@ def __str__(self): return value + left + right -def split(root: Node, value: int) -> Tuple[Node, Node]: +def split(root: Node, value: int) -> tuple[Node, Node]: """ We split current tree into 2 trees with value: diff --git a/data_structures/linked_list/skip_list.py b/data_structures/linked_list/skip_list.py index ee572cd3ed19..8f06e6193d52 100644 --- a/data_structures/linked_list/skip_list.py +++ b/data_structures/linked_list/skip_list.py @@ -3,8 +3,10 @@ https://epaperpress.com/sortsearch/download/skiplist.pdf """ +from __future__ import annotations + from random import random -from typing import Generic, List, Optional, Tuple, TypeVar +from typing import Generic, Optional, TypeVar KT = TypeVar("KT") VT = TypeVar("VT") @@ -14,7 +16,7 @@ class Node(Generic[KT, VT]): def __init__(self, key: KT, value: VT): self.key = key self.value = value - self.forward: List[Node[KT, VT]] = [] + self.forward: list[Node[KT, VT]] = [] def __repr__(self) -> str: """ @@ -122,7 +124,7 @@ def random_level(self) -> int: return level - def _locate_node(self, key) -> Tuple[Optional[Node[KT, VT]], List[Node[KT, VT]]]: + def _locate_node(self, key) -> tuple[Optional[Node[KT, VT]], list[Node[KT, VT]]]: """ :param key: Searched key, :return: Tuple with searched node (or None if given key is not present) diff --git a/divide_and_conquer/strassen_matrix_multiplication.py b/divide_and_conquer/strassen_matrix_multiplication.py index 486258e8bae0..29a174daebf9 100644 --- a/divide_and_conquer/strassen_matrix_multiplication.py +++ b/divide_and_conquer/strassen_matrix_multiplication.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import math -from typing import List, Tuple -def default_matrix_multiplication(a: List, b: List) -> List: +def default_matrix_multiplication(a: list, b: list) -> list: """ Multiplication only for 2x2 matrices """ @@ -15,23 +16,21 @@ def default_matrix_multiplication(a: List, b: List) -> List: return new_matrix -def matrix_addition(matrix_a: List, matrix_b: List): +def matrix_addition(matrix_a: list, matrix_b: list): return [ [matrix_a[row][col] + matrix_b[row][col] for col in range(len(matrix_a[row]))] for row in range(len(matrix_a)) ] -def matrix_subtraction(matrix_a: List, matrix_b: List): +def matrix_subtraction(matrix_a: list, matrix_b: list): return [ [matrix_a[row][col] - matrix_b[row][col] for col in range(len(matrix_a[row]))] for row in range(len(matrix_a)) ] -def split_matrix( - a: List, -) -> Tuple[List, List, List, List]: +def split_matrix(a: list) -> tuple[list, list, list, list]: """ Given an even length matrix, returns the top_left, top_right, bot_left, bot_right quadrant. @@ -64,16 +63,16 @@ def split_matrix( return top_left, top_right, bot_left, bot_right -def matrix_dimensions(matrix: List) -> Tuple[int, int]: +def matrix_dimensions(matrix: list) -> tuple[int, int]: return len(matrix), len(matrix[0]) -def print_matrix(matrix: List) -> None: +def print_matrix(matrix: list) -> None: for i in range(len(matrix)): print(matrix[i]) -def actual_strassen(matrix_a: List, matrix_b: List) -> List: +def actual_strassen(matrix_a: list, matrix_b: list) -> list: """ Recursive function to calculate the product of two matrices, using the Strassen Algorithm. It only supports even length matrices. @@ -106,7 +105,7 @@ def actual_strassen(matrix_a: List, matrix_b: List) -> List: return new_matrix -def strassen(matrix1: List, matrix2: List) -> List: +def strassen(matrix1: list, matrix2: list) -> list: """ >>> strassen([[2,1,3],[3,4,6],[1,4,2],[7,6,7]], [[4,2,3,4],[2,1,1,1],[8,6,4,2]]) [[34, 23, 19, 15], [68, 46, 37, 28], [28, 18, 15, 12], [96, 62, 55, 48]] diff --git a/dynamic_programming/fast_fibonacci.py b/dynamic_programming/fast_fibonacci.py index 63481fe70a92..f48186a34c25 100644 --- a/dynamic_programming/fast_fibonacci.py +++ b/dynamic_programming/fast_fibonacci.py @@ -4,8 +4,9 @@ This program calculates the nth Fibonacci number in O(log(n)). It's possible to calculate F(1_000_000) in less than a second. """ +from __future__ import annotations + import sys -from typing import Tuple def fibonacci(n: int) -> int: @@ -20,7 +21,7 @@ def fibonacci(n: int) -> int: # returns (F(n), F(n-1)) -def _fib(n: int) -> Tuple[int, int]: +def _fib(n: int) -> tuple[int, int]: if n == 0: # (F(0), F(1)) return (0, 1) diff --git a/dynamic_programming/fractional_knapsack_2.py b/dynamic_programming/fractional_knapsack_2.py index eadb73c61a39..cae57738311b 100644 --- a/dynamic_programming/fractional_knapsack_2.py +++ b/dynamic_programming/fractional_knapsack_2.py @@ -2,12 +2,12 @@ # https://www.guru99.com/fractional-knapsack-problem-greedy.html # https://medium.com/walkinthecode/greedy-algorithm-fractional-knapsack-problem-9aba1daecc93 -from typing import List, Tuple +from __future__ import annotations def fractional_knapsack( - value: List[int], weight: List[int], capacity: int -) -> Tuple[int, List[int]]: + value: list[int], weight: list[int], capacity: int +) -> tuple[int, list[int]]: """ >>> value = [1, 3, 5, 7, 9] >>> weight = [0.9, 0.7, 0.5, 0.3, 0.1] diff --git a/dynamic_programming/iterating_through_submasks.py b/dynamic_programming/iterating_through_submasks.py index cb27a5b884bd..855af61d6707 100644 --- a/dynamic_programming/iterating_through_submasks.py +++ b/dynamic_programming/iterating_through_submasks.py @@ -5,10 +5,10 @@ its submasks. The mask s is submask of m if only bits that were included in bitmask are set """ -from typing import List +from __future__ import annotations -def list_of_submasks(mask: int) -> List[int]: +def list_of_submasks(mask: int) -> list[int]: """ Args: diff --git a/dynamic_programming/longest_increasing_subsequence.py b/dynamic_programming/longest_increasing_subsequence.py index 48d5e8e8fade..f5ca8a2b5cdc 100644 --- a/dynamic_programming/longest_increasing_subsequence.py +++ b/dynamic_programming/longest_increasing_subsequence.py @@ -10,10 +10,10 @@ Example: [10, 22, 9, 33, 21, 50, 41, 60, 80] as input will return [10, 22, 33, 41, 60, 80] as output """ -from typing import List +from __future__ import annotations -def longest_subsequence(array: List[int]) -> List[int]: # This function is recursive +def longest_subsequence(array: list[int]) -> list[int]: # This function is recursive """ Some examples >>> longest_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80]) diff --git a/dynamic_programming/longest_increasing_subsequence_o(nlogn).py b/dynamic_programming/longest_increasing_subsequence_o(nlogn).py index b33774057db3..af536f8bbd01 100644 --- a/dynamic_programming/longest_increasing_subsequence_o(nlogn).py +++ b/dynamic_programming/longest_increasing_subsequence_o(nlogn).py @@ -4,7 +4,7 @@ # comments: This programme outputs the Longest Strictly Increasing Subsequence in # O(NLogN) Where N is the Number of elements in the list ############################# -from typing import List +from __future__ import annotations def CeilIndex(v, l, r, key): # noqa: E741 @@ -17,7 +17,7 @@ def CeilIndex(v, l, r, key): # noqa: E741 return r -def LongestIncreasingSubsequenceLength(v: List[int]) -> int: +def LongestIncreasingSubsequenceLength(v: list[int]) -> int: """ >>> LongestIncreasingSubsequenceLength([2, 5, 3, 7, 11, 8, 10, 13, 6]) 6 diff --git a/dynamic_programming/max_non_adjacent_sum.py b/dynamic_programming/max_non_adjacent_sum.py index 15dd8ce664ed..5362b22ca9dc 100644 --- a/dynamic_programming/max_non_adjacent_sum.py +++ b/dynamic_programming/max_non_adjacent_sum.py @@ -1,9 +1,9 @@ # Video Explanation: https://www.youtube.com/watch?v=6w60Zi1NtL8&feature=emb_logo -from typing import List +from __future__ import annotations -def maximum_non_adjacent_sum(nums: List[int]) -> int: +def maximum_non_adjacent_sum(nums: list[int]) -> int: """ Find the maximum non-adjacent sum of the integers in the nums input list diff --git a/dynamic_programming/max_sub_array.py b/dynamic_programming/max_sub_array.py index 1ca4f90bbaa2..3060010ef7c6 100644 --- a/dynamic_programming/max_sub_array.py +++ b/dynamic_programming/max_sub_array.py @@ -1,7 +1,7 @@ """ author : Mayank Kumar Jha (mk9440) """ -from typing import List +from __future__ import annotations def find_max_sub_array(A, low, high): @@ -38,7 +38,7 @@ def find_max_cross_sum(A, low, mid, high): return max_left, max_right, (left_sum + right_sum) -def max_sub_array(nums: List[int]) -> int: +def max_sub_array(nums: list[int]) -> int: """ Finds the contiguous subarray which has the largest sum and return its sum. diff --git a/dynamic_programming/minimum_cost_path.py b/dynamic_programming/minimum_cost_path.py index 09295a4fafbe..3ad24b5528d1 100644 --- a/dynamic_programming/minimum_cost_path.py +++ b/dynamic_programming/minimum_cost_path.py @@ -1,9 +1,9 @@ # Youtube Explanation: https://www.youtube.com/watch?v=lBRtnuxg-gU -from typing import List +from __future__ import annotations -def minimum_cost_path(matrix: List[List[int]]) -> int: +def minimum_cost_path(matrix: list[list[int]]) -> int: """ Find the minimum cost traced by all possible paths from top left to bottom right in a given matrix diff --git a/genetic_algorithm/basic_string.py b/genetic_algorithm/basic_string.py index 482a6cb5e656..97dbe182bc82 100644 --- a/genetic_algorithm/basic_string.py +++ b/genetic_algorithm/basic_string.py @@ -5,8 +5,9 @@ Author: D4rkia """ +from __future__ import annotations + import random -from typing import List, Tuple # Maximum size of the population. bigger could be faster but is more memory expensive N_POPULATION = 200 @@ -20,7 +21,7 @@ random.seed(random.randint(0, 1000)) -def basic(target: str, genes: List[str], debug: bool = True) -> Tuple[int, int, str]: +def basic(target: str, genes: list[str], debug: bool = True) -> tuple[int, int, str]: """ Verify that the target contains no genes besides the ones inside genes variable. @@ -69,7 +70,7 @@ def basic(target: str, genes: List[str], debug: bool = True) -> Tuple[int, int, total_population += len(population) # Random population created now it's time to evaluate - def evaluate(item: str, main_target: str = target) -> Tuple[str, float]: + def evaluate(item: str, main_target: str = target) -> tuple[str, float]: """ Evaluate how similar the item is with the target by just counting each char in the right position @@ -84,7 +85,7 @@ def evaluate(item: str, main_target: str = target) -> Tuple[str, float]: # Adding a bit of concurrency can make everything faster, # # import concurrent.futures - # population_score: List[Tuple[str, float]] = [] + # population_score: list[tuple[str, float]] = [] # with concurrent.futures.ThreadPoolExecutor( # max_workers=NUM_WORKERS) as executor: # futures = {executor.submit(evaluate, item) for item in population} @@ -121,7 +122,7 @@ def evaluate(item: str, main_target: str = target) -> Tuple[str, float]: ] # Select, Crossover and Mutate a new population - def select(parent_1: Tuple[str, float]) -> List[str]: + def select(parent_1: tuple[str, float]) -> list[str]: """Select the second parent and generate new population""" pop = [] # Generate more child proportionally to the fitness score @@ -135,7 +136,7 @@ def select(parent_1: Tuple[str, float]) -> List[str]: pop.append(mutate(child_2)) return pop - def crossover(parent_1: str, parent_2: str) -> Tuple[str, str]: + def crossover(parent_1: str, parent_2: str) -> tuple[str, str]: """Slice and combine two string in a random point""" random_slice = random.randint(0, len(parent_1) - 1) child_1 = parent_1[:random_slice] + parent_2[random_slice:] diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index 48755647e02d..295ff47e8cdc 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -1,6 +1,6 @@ # https://en.wikipedia.org/wiki/B%C3%A9zier_curve # https://www.tutorialspoint.com/computer_graphics/computer_graphics_curves.htm -from typing import List, Tuple +from __future__ import annotations from scipy.special import comb @@ -12,7 +12,7 @@ class BezierCurve: This implementation works only for 2d coordinates in the xy plane. """ - def __init__(self, list_of_points: List[Tuple[float, float]]): + def __init__(self, list_of_points: list[tuple[float, float]]): """ list_of_points: Control points in the xy plane on which to interpolate. These points control the behavior (shape) of the Bezier curve. @@ -22,7 +22,7 @@ def __init__(self, list_of_points: List[Tuple[float, float]]): # Degree = 1 will produce a straight line. self.degree = len(list_of_points) - 1 - def basis_function(self, t: float) -> List[float]: + def basis_function(self, t: float) -> list[float]: """ The basis function determines the weight of each control point at time t. t: time value between 0 and 1 inclusive at which to evaluate the basis of @@ -36,7 +36,7 @@ def basis_function(self, t: float) -> List[float]: [0.0, 1.0] """ assert 0 <= t <= 1, "Time t must be between 0 and 1." - output_values: List[float] = [] + output_values: list[float] = [] for i in range(len(self.list_of_points)): # basis function for each i output_values.append( @@ -46,7 +46,7 @@ def basis_function(self, t: float) -> List[float]: assert round(sum(output_values), 5) == 1 return output_values - def bezier_curve_function(self, t: float) -> Tuple[float, float]: + def bezier_curve_function(self, t: float) -> tuple[float, float]: """ The function to produce the values of the Bezier curve at time t. t: the value of time t at which to evaluate the Bezier function @@ -80,8 +80,8 @@ def plot_curve(self, step_size: float = 0.01): """ from matplotlib import pyplot as plt - to_plot_x: List[float] = [] # x coordinates of points to plot - to_plot_y: List[float] = [] # y coordinates of points to plot + to_plot_x: list[float] = [] # x coordinates of points to plot + to_plot_y: list[float] = [] # y coordinates of points to plot t = 0.0 while t <= 1: diff --git a/graphs/bellman_ford.py b/graphs/bellman_ford.py index d4d37a365e03..ace7985647bb 100644 --- a/graphs/bellman_ford.py +++ b/graphs/bellman_ford.py @@ -1,4 +1,4 @@ -from typing import Dict, List +from __future__ import annotations def printDist(dist, V): @@ -7,7 +7,7 @@ def printDist(dist, V): print("\t".join(f"{i}\t{d}" for i, d in enumerate(distances))) -def BellmanFord(graph: List[Dict[str, int]], V: int, E: int, src: int) -> int: +def BellmanFord(graph: list[dict[str, int]], V: int, E: int, src: int) -> int: """ Returns shortest paths from a vertex src to all other vertices. diff --git a/graphs/bidirectional_a_star.py b/graphs/bidirectional_a_star.py index 76313af769be..72ff4fa65ff0 100644 --- a/graphs/bidirectional_a_star.py +++ b/graphs/bidirectional_a_star.py @@ -2,9 +2,10 @@ https://en.wikipedia.org/wiki/Bidirectional_search """ +from __future__ import annotations + import time from math import sqrt -from typing import List, Tuple # 1 for manhattan, 0 for euclidean HEURISTIC = 0 @@ -89,7 +90,7 @@ def __init__(self, start, goal): self.reached = False - def search(self) -> List[Tuple[int]]: + def search(self) -> list[tuple[int]]: while self.open_nodes: # Open Nodes are sorted using __lt__ self.open_nodes.sort() @@ -120,7 +121,7 @@ def search(self) -> List[Tuple[int]]: if not (self.reached): return [(self.start.pos)] - def get_successors(self, parent: Node) -> List[Node]: + def get_successors(self, parent: Node) -> list[Node]: """ Returns a list of successors (both in the grid and free spaces) """ @@ -146,7 +147,7 @@ def get_successors(self, parent: Node) -> List[Node]: ) return successors - def retrace_path(self, node: Node) -> List[Tuple[int]]: + def retrace_path(self, node: Node) -> list[tuple[int]]: """ Retrace the path from parents to parents until start node """ @@ -177,7 +178,7 @@ def __init__(self, start, goal): self.bwd_astar = AStar(goal, start) self.reached = False - def search(self) -> List[Tuple[int]]: + def search(self) -> list[tuple[int]]: while self.fwd_astar.open_nodes or self.bwd_astar.open_nodes: self.fwd_astar.open_nodes.sort() self.bwd_astar.open_nodes.sort() @@ -224,7 +225,7 @@ def search(self) -> List[Tuple[int]]: def retrace_bidirectional_path( self, fwd_node: Node, bwd_node: Node - ) -> List[Tuple[int]]: + ) -> list[tuple[int]]: fwd_path = self.fwd_astar.retrace_path(fwd_node) bwd_path = self.bwd_astar.retrace_path(bwd_node) bwd_path.pop() diff --git a/graphs/bidirectional_breadth_first_search.py b/graphs/bidirectional_breadth_first_search.py index d941c0db5893..39d8dc7d4187 100644 --- a/graphs/bidirectional_breadth_first_search.py +++ b/graphs/bidirectional_breadth_first_search.py @@ -2,8 +2,9 @@ https://en.wikipedia.org/wiki/Bidirectional_search """ +from __future__ import annotations + import time -from typing import List, Tuple grid = [ [0, 0, 0, 0, 0, 0, 0], @@ -51,7 +52,7 @@ def __init__(self, start, goal): self.node_queue = [self.start] self.reached = False - def search(self) -> List[Tuple[int]]: + def search(self) -> list[tuple[int]]: while self.node_queue: current_node = self.node_queue.pop(0) @@ -67,7 +68,7 @@ def search(self) -> List[Tuple[int]]: if not (self.reached): return [(self.start.pos)] - def get_successors(self, parent: Node) -> List[Node]: + def get_successors(self, parent: Node) -> list[Node]: """ Returns a list of successors (both in the grid and free spaces) """ @@ -86,7 +87,7 @@ def get_successors(self, parent: Node) -> List[Node]: ) return successors - def retrace_path(self, node: Node) -> List[Tuple[int]]: + def retrace_path(self, node: Node) -> list[tuple[int]]: """ Retrace the path from parents to parents until start node """ @@ -118,7 +119,7 @@ def __init__(self, start, goal): self.bwd_bfs = BreadthFirstSearch(goal, start) self.reached = False - def search(self) -> List[Tuple[int]]: + def search(self) -> list[tuple[int]]: while self.fwd_bfs.node_queue or self.bwd_bfs.node_queue: current_fwd_node = self.fwd_bfs.node_queue.pop(0) current_bwd_node = self.bwd_bfs.node_queue.pop(0) @@ -146,7 +147,7 @@ def search(self) -> List[Tuple[int]]: def retrace_bidirectional_path( self, fwd_node: Node, bwd_node: Node - ) -> List[Tuple[int]]: + ) -> list[tuple[int]]: fwd_path = self.fwd_bfs.retrace_path(fwd_node) bwd_path = self.bwd_bfs.retrace_path(bwd_node) bwd_path.pop() diff --git a/graphs/breadth_first_search_2.py b/graphs/breadth_first_search_2.py index 293a1012f61f..a90e963a4043 100644 --- a/graphs/breadth_first_search_2.py +++ b/graphs/breadth_first_search_2.py @@ -12,7 +12,7 @@ mark w as explored add w to Q (at the end) """ -from typing import Dict, Set +from __future__ import annotations G = { "A": ["B", "C"], @@ -24,7 +24,7 @@ } -def breadth_first_search(graph: Dict, start: str) -> Set[str]: +def breadth_first_search(graph: dict, start: str) -> set[str]: """ >>> ''.join(sorted(breadth_first_search(G, 'A'))) 'ABCDEF' diff --git a/graphs/breadth_first_search_shortest_path.py b/graphs/breadth_first_search_shortest_path.py index c25a5bb4f7dd..b43479d4659c 100644 --- a/graphs/breadth_first_search_shortest_path.py +++ b/graphs/breadth_first_search_shortest_path.py @@ -1,7 +1,7 @@ """Breath First Search (BFS) can be used when finding the shortest path from a given source node to a target node in an unweighted graph. """ -from typing import Dict +from __future__ import annotations graph = { "A": ["B", "C", "E"], @@ -15,7 +15,7 @@ class Graph: - def __init__(self, graph: Dict[str, str], source_vertex: str) -> None: + def __init__(self, graph: dict[str, str], source_vertex: str) -> None: """Graph is implemented as dictionary of adjacency lists. Also, Source vertex have to be defined upon initialization. """ diff --git a/graphs/depth_first_search.py b/graphs/depth_first_search.py index 43f2eaaea19a..907cc172f253 100644 --- a/graphs/depth_first_search.py +++ b/graphs/depth_first_search.py @@ -1,9 +1,9 @@ """Non recursive implementation of a DFS algorithm.""" -from typing import Dict, Set +from __future__ import annotations -def depth_first_search(graph: Dict, start: str) -> Set[int]: +def depth_first_search(graph: dict, start: str) -> set[int]: """Depth First Search on Graph :param graph: directed graph in dictionary format :param vertex: starting vertex as a string diff --git a/graphs/gale_shapley_bigraph.py b/graphs/gale_shapley_bigraph.py index 07a3922f86ec..59baf8296ea6 100644 --- a/graphs/gale_shapley_bigraph.py +++ b/graphs/gale_shapley_bigraph.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def stable_matching(donor_pref: List[int], recipient_pref: List[int]) -> List[int]: +def stable_matching(donor_pref: list[int], recipient_pref: list[int]) -> list[int]: """ Finds the stable match in any bipartite graph, i.e a pairing where no 2 objects prefer each other over their partner. The function accepts the preferences of diff --git a/graphs/greedy_best_first.py b/graphs/greedy_best_first.py index 2e63a50ce30a..4b80a6853d3f 100644 --- a/graphs/greedy_best_first.py +++ b/graphs/greedy_best_first.py @@ -2,7 +2,7 @@ https://en.wikipedia.org/wiki/Best-first_search#Greedy_BFS """ -from typing import List, Tuple +from __future__ import annotations grid = [ [0, 0, 0, 0, 0, 0, 0], @@ -81,7 +81,7 @@ def __init__(self, start, goal): self.reached = False - def search(self) -> List[Tuple[int]]: + def search(self) -> list[tuple[int]]: """ Search for the path, if a path is not found, only the starting position is returned @@ -116,7 +116,7 @@ def search(self) -> List[Tuple[int]]: if not (self.reached): return [self.start.pos] - def get_successors(self, parent: Node) -> List[Node]: + def get_successors(self, parent: Node) -> list[Node]: """ Returns a list of successors (both in the grid and free spaces) """ @@ -143,7 +143,7 @@ def get_successors(self, parent: Node) -> List[Node]: ) return successors - def retrace_path(self, node: Node) -> List[Tuple[int]]: + def retrace_path(self, node: Node) -> list[tuple[int]]: """ Retrace the path from parents to parents until start node """ diff --git a/graphs/karger.py b/graphs/karger.py index baa0eebd90b4..f72128c8178a 100644 --- a/graphs/karger.py +++ b/graphs/karger.py @@ -2,8 +2,9 @@ An implementation of Karger's Algorithm for partitioning a graph. """ +from __future__ import annotations + import random -from typing import Dict, List, Set, Tuple # Adjacency list representation of this graph: # https://en.wikipedia.org/wiki/File:Single_run_of_Karger%E2%80%99s_Mincut_algorithm.svg @@ -21,7 +22,7 @@ } -def partition_graph(graph: Dict[str, List[str]]) -> Set[Tuple[str, str]]: +def partition_graph(graph: dict[str, list[str]]) -> set[tuple[str, str]]: """ Partitions a graph using Karger's Algorithm. Implemented from pseudocode found here: @@ -60,9 +61,7 @@ def partition_graph(graph: Dict[str, List[str]]) -> Set[Tuple[str, str]]: for neighbor in uv_neighbors: graph_copy[neighbor].append(uv) - contracted_nodes[uv] = { - node for node in contracted_nodes[u].union(contracted_nodes[v]) - } + contracted_nodes[uv] = set(contracted_nodes[u].union(contracted_nodes[v])) # Remove nodes u and v. del graph_copy[u] diff --git a/graphs/prim.py b/graphs/prim.py index f7376cfb48ca..70329da7e8e2 100644 --- a/graphs/prim.py +++ b/graphs/prim.py @@ -100,7 +100,7 @@ def prim_heap(graph: list, root: Vertex) -> Iterator[tuple]: u.pi = None root.key = 0 - h = [v for v in graph] + h = list(graph) hq.heapify(h) while h: diff --git a/linear_algebra/src/polynom_for_points.py b/linear_algebra/src/polynom_for_points.py index 8db89fc2c1ea..7a363723d9d2 100644 --- a/linear_algebra/src/polynom_for_points.py +++ b/linear_algebra/src/polynom_for_points.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def points_to_polynomial(coordinates: List[List[int]]) -> str: +def points_to_polynomial(coordinates: list[list[int]]) -> str: """ coordinates is a two dimensional matrix: [[x, y], [x, y], ...] number of points you want to use @@ -60,7 +60,7 @@ def points_to_polynomial(coordinates: List[List[int]]) -> str: while count_of_line < x: count_in_line = 0 a = coordinates[count_of_line][0] - count_line: List[int] = [] + count_line: list[int] = [] while count_in_line < x: count_line.append(a ** (x - (count_in_line + 1))) count_in_line += 1 @@ -69,7 +69,7 @@ def points_to_polynomial(coordinates: List[List[int]]) -> str: count_of_line = 0 # put the y values into a vector - vector: List[int] = [] + vector: list[int] = [] while count_of_line < x: vector.append(coordinates[count_of_line][1]) count_of_line += 1 @@ -94,7 +94,7 @@ def points_to_polynomial(coordinates: List[List[int]]) -> str: count = 0 # make solutions - solution: List[str] = [] + solution: list[str] = [] while count < x: solution.append(vector[count] / matrix[count][count]) count += 1 @@ -103,7 +103,7 @@ def points_to_polynomial(coordinates: List[List[int]]) -> str: solved = "f(x)=" while count < x: - remove_e: List[str] = str(solution[count]).split("E") + remove_e: list[str] = str(solution[count]).split("E") if len(remove_e) > 1: solution[count] = remove_e[0] + "*10^" + remove_e[1] solved += "x^" + str(x - (count + 1)) + "*" + str(solution[count]) diff --git a/linear_algebra/src/transformations_2d.py b/linear_algebra/src/transformations_2d.py index 9ee238fd7999..6a15189c5676 100644 --- a/linear_algebra/src/transformations_2d.py +++ b/linear_algebra/src/transformations_2d.py @@ -11,11 +11,12 @@ reflection(45) = [[0.05064397763545947, 0.893996663600558], [0.893996663600558, 0.7018070490682369]] """ +from __future__ import annotations + from math import cos, sin -from typing import List -def scaling(scaling_factor: float) -> List[List[float]]: +def scaling(scaling_factor: float) -> list[list[float]]: """ >>> scaling(5) [[5.0, 0.0], [0.0, 5.0]] @@ -24,7 +25,7 @@ def scaling(scaling_factor: float) -> List[List[float]]: return [[scaling_factor * int(x == y) for x in range(2)] for y in range(2)] -def rotation(angle: float) -> List[List[float]]: +def rotation(angle: float) -> list[list[float]]: """ >>> rotation(45) # doctest: +NORMALIZE_WHITESPACE [[0.5253219888177297, -0.8509035245341184], @@ -34,7 +35,7 @@ def rotation(angle: float) -> List[List[float]]: return [[c, -s], [s, c]] -def projection(angle: float) -> List[List[float]]: +def projection(angle: float) -> list[list[float]]: """ >>> projection(45) # doctest: +NORMALIZE_WHITESPACE [[0.27596319193541496, 0.446998331800279], @@ -45,7 +46,7 @@ def projection(angle: float) -> List[List[float]]: return [[c * c, cs], [cs, s * s]] -def reflection(angle: float) -> List[List[float]]: +def reflection(angle: float) -> list[list[float]]: """ >>> reflection(45) # doctest: +NORMALIZE_WHITESPACE [[0.05064397763545947, 0.893996663600558], diff --git a/maths/3n_plus_1.py b/maths/3n_plus_1.py index baaa74f89bf5..28c9fd7b426f 100644 --- a/maths/3n_plus_1.py +++ b/maths/3n_plus_1.py @@ -1,7 +1,7 @@ -from typing import List, Tuple +from __future__ import annotations -def n31(a: int) -> Tuple[List[int], int]: +def n31(a: int) -> tuple[list[int], int]: """ Returns the Collatz sequence and its length of any positive integer. >>> n31(4) diff --git a/maths/abs_max.py b/maths/abs_max.py index 554e27f6ee66..e5a8219657ac 100644 --- a/maths/abs_max.py +++ b/maths/abs_max.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def abs_max(x: List[int]) -> int: +def abs_max(x: list[int]) -> int: """ >>> abs_max([0,5,1,11]) 11 diff --git a/maths/allocation_number.py b/maths/allocation_number.py index c6f1e562f878..4e74bb2e6950 100644 --- a/maths/allocation_number.py +++ b/maths/allocation_number.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def allocation_num(number_of_bytes: int, partitions: int) -> List[str]: +def allocation_num(number_of_bytes: int, partitions: int) -> list[str]: """ Divide a number of bytes into x partitions. diff --git a/maths/collatz_sequence.py b/maths/collatz_sequence.py index 6ace77312732..7b3636de69f4 100644 --- a/maths/collatz_sequence.py +++ b/maths/collatz_sequence.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def collatz_sequence(n: int) -> List[int]: +def collatz_sequence(n: int) -> list[int]: """ Collatz conjecture: start with any positive integer n. The next term is obtained as follows: diff --git a/maths/entropy.py b/maths/entropy.py index c380afd3b5c9..74980ef9e0c6 100644 --- a/maths/entropy.py +++ b/maths/entropy.py @@ -4,11 +4,11 @@ Implementation of entropy of information https://en.wikipedia.org/wiki/Entropy_(information_theory) """ +from __future__ import annotations import math from collections import Counter from string import ascii_lowercase -from typing import Tuple def calculate_prob(text: str) -> None: @@ -89,7 +89,7 @@ def calculate_prob(text: str) -> None: print("{0:.1f}".format(round(((-1 * my_sec_sum) - (-1 * my_fir_sum))))) -def analyze_text(text: str) -> Tuple[dict, dict]: +def analyze_text(text: str) -> tuple[dict, dict]: """ Convert text input into two dicts of counts. The first dictionary stores the frequency of single character strings. diff --git a/maths/is_square_free.py b/maths/is_square_free.py index 6d27d0af3387..8d83d95ffb67 100644 --- a/maths/is_square_free.py +++ b/maths/is_square_free.py @@ -3,10 +3,10 @@ python/black : True flake8 : True """ -from typing import List +from __future__ import annotations -def is_square_free(factors: List[int]) -> bool: +def is_square_free(factors: list[int]) -> bool: """ # doctest: +NORMALIZE_WHITESPACE This functions takes a list of prime factors as input. diff --git a/maths/line_length.py b/maths/line_length.py index 6df0a916efe6..1d386b44b50d 100644 --- a/maths/line_length.py +++ b/maths/line_length.py @@ -1,4 +1,4 @@ -import math as m +import math from typing import Callable, Union @@ -29,7 +29,7 @@ def line_length( '10.000000' >>> def f(x): - ... return m.sin(5 * x) + m.cos(10 * x) + x * x/10 + ... return math.sin(5 * x) + math.cos(10 * x) + x * x/10 >>> f"{line_length(f, 0.0, 10.0, 10000):.6f}" '69.534930' """ @@ -43,7 +43,7 @@ def line_length( # Approximates curve as a sequence of linear lines and sums their length x2 = (x_end - x_start) / steps + x1 fx2 = fnc(x2) - length += m.hypot(x2 - x1, fx2 - fx1) + length += math.hypot(x2 - x1, fx2 - fx1) # Increment step x1 = x2 @@ -55,7 +55,7 @@ def line_length( if __name__ == "__main__": def f(x): - return m.sin(10 * x) + return math.sin(10 * x) print("f(x) = sin(10 * x)") print("The length of the curve from x = -10 to x = 10 is:") diff --git a/maths/monte_carlo_dice.py b/maths/monte_carlo_dice.py index c36c3e83e00b..e8e3abe83a99 100644 --- a/maths/monte_carlo_dice.py +++ b/maths/monte_carlo_dice.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import random -from typing import List class Dice: @@ -16,7 +17,7 @@ def _str_(self): return "Fair Dice" -def throw_dice(num_throws: int, num_dice: int = 2) -> List[float]: +def throw_dice(num_throws: int, num_dice: int = 2) -> list[float]: """ Return probability list of all possible sums when throwing dice. @@ -35,7 +36,7 @@ def throw_dice(num_throws: int, num_dice: int = 2) -> List[float]: dices = [Dice() for i in range(num_dice)] count_of_sum = [0] * (len(dices) * Dice.NUM_SIDES + 1) for i in range(num_throws): - count_of_sum[sum([dice.roll() for dice in dices])] += 1 + count_of_sum[sum(dice.roll() for dice in dices)] += 1 probability = [round((count * 100) / num_throws, 2) for count in count_of_sum] return probability[num_dice:] # remove probability of sums that never appear diff --git a/maths/prime_factors.py b/maths/prime_factors.py index 34795dd98d1a..e520ae3a6d04 100644 --- a/maths/prime_factors.py +++ b/maths/prime_factors.py @@ -1,10 +1,10 @@ """ python/black : True """ -from typing import List +from __future__ import annotations -def prime_factors(n: int) -> List[int]: +def prime_factors(n: int) -> list[int]: """ Returns prime factors of n as a list. diff --git a/maths/quadratic_equations_complex_numbers.py b/maths/quadratic_equations_complex_numbers.py index 7c47bdef2297..01a411bc560d 100644 --- a/maths/quadratic_equations_complex_numbers.py +++ b/maths/quadratic_equations_complex_numbers.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from cmath import sqrt -from typing import Tuple -def quadratic_roots(a: int, b: int, c: int) -> Tuple[complex, complex]: +def quadratic_roots(a: int, b: int, c: int) -> tuple[complex, complex]: """ Given the numerical coefficients a, b and c, calculates the roots for any quadratic equation of the form ax^2 + bx + c diff --git a/maths/relu.py b/maths/relu.py index 826ada65fa16..458c6bd5c391 100644 --- a/maths/relu.py +++ b/maths/relu.py @@ -9,12 +9,12 @@ Script inspired from its corresponding Wikipedia article https://en.wikipedia.org/wiki/Rectifier_(neural_networks) """ -from typing import List +from __future__ import annotations import numpy as np -def relu(vector: List[float]): +def relu(vector: list[float]): """ Implements the relu function diff --git a/matrix/inverse_of_matrix.py b/matrix/inverse_of_matrix.py index abbeb79ddbdb..9deca6c3c08e 100644 --- a/matrix/inverse_of_matrix.py +++ b/matrix/inverse_of_matrix.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from decimal import Decimal -from typing import List -def inverse_of_matrix(matrix: List[List[float]]) -> List[List[float]]: +def inverse_of_matrix(matrix: list[list[float]]) -> list[list[float]]: """ A matrix multiplied with its inverse gives the identity matrix. This function finds the inverse of a 2x2 matrix. diff --git a/matrix/matrix_operation.py b/matrix/matrix_operation.py index 3838dab6be09..dca01f9c3183 100644 --- a/matrix/matrix_operation.py +++ b/matrix/matrix_operation.py @@ -2,10 +2,10 @@ Functions for 2D matrix operations """ -from typing import List, Tuple +from __future__ import annotations -def add(*matrix_s: List[list]) -> List[list]: +def add(*matrix_s: list[list]) -> list[list]: """ >>> add([[1,2],[3,4]],[[2,3],[4,5]]) [[3, 5], [7, 9]] @@ -20,7 +20,7 @@ def add(*matrix_s: List[list]) -> List[list]: return [[sum(t) for t in zip(*m)] for m in zip(*matrix_s)] -def subtract(matrix_a: List[list], matrix_b: List[list]) -> List[list]: +def subtract(matrix_a: list[list], matrix_b: list[list]) -> list[list]: """ >>> subtract([[1,2],[3,4]],[[2,3],[4,5]]) [[-1, -1], [-1, -1]] @@ -35,7 +35,7 @@ def subtract(matrix_a: List[list], matrix_b: List[list]) -> List[list]: return [[i - j for i, j in zip(*m)] for m in zip(matrix_a, matrix_b)] -def scalar_multiply(matrix: List[list], n: int) -> List[list]: +def scalar_multiply(matrix: list[list], n: int) -> list[list]: """ >>> scalar_multiply([[1,2],[3,4]],5) [[5, 10], [15, 20]] @@ -45,7 +45,7 @@ def scalar_multiply(matrix: List[list], n: int) -> List[list]: return [[x * n for x in row] for row in matrix] -def multiply(matrix_a: List[list], matrix_b: List[list]) -> List[list]: +def multiply(matrix_a: list[list], matrix_b: list[list]) -> list[list]: """ >>> multiply([[1,2],[3,4]],[[5,5],[7,5]]) [[19, 15], [43, 35]] @@ -67,7 +67,7 @@ def multiply(matrix_a: List[list], matrix_b: List[list]) -> List[list]: ] -def identity(n: int) -> List[list]: +def identity(n: int) -> list[list]: """ :param n: dimension for nxn matrix :type n: int @@ -79,7 +79,7 @@ def identity(n: int) -> List[list]: return [[int(row == column) for column in range(n)] for row in range(n)] -def transpose(matrix: List[list], return_map: bool = True) -> List[list]: +def transpose(matrix: list[list], return_map: bool = True) -> list[list]: """ >>> transpose([[1,2],[3,4]]) # doctest: +ELLIPSIS List[list]: return list(map(list, zip(*matrix))) -def minor(matrix: List[list], row: int, column: int) -> List[list]: +def minor(matrix: list[list], row: int, column: int) -> list[list]: """ >>> minor([[1, 2], [3, 4]], 1, 1) [[1]] @@ -102,7 +102,7 @@ def minor(matrix: List[list], row: int, column: int) -> List[list]: return [row[:column] + row[column + 1 :] for row in minor] -def determinant(matrix: List[list]) -> int: +def determinant(matrix: list[list]) -> int: """ >>> determinant([[1, 2], [3, 4]]) -2 @@ -118,7 +118,7 @@ def determinant(matrix: List[list]) -> int: ) -def inverse(matrix: List[list]) -> List[list]: +def inverse(matrix: list[list]) -> list[list]: """ >>> inverse([[1, 2], [3, 4]]) [[-2.0, 1.0], [1.5, -0.5]] @@ -142,17 +142,17 @@ def inverse(matrix: List[list]) -> List[list]: return scalar_multiply(adjugate, 1 / det) -def _check_not_integer(matrix: List[list]) -> bool: +def _check_not_integer(matrix: list[list]) -> bool: if not isinstance(matrix, int) and not isinstance(matrix[0], int): return True raise TypeError("Expected a matrix, got int/list instead") -def _shape(matrix: List[list]) -> list: +def _shape(matrix: list[list]) -> list: return len(matrix), len(matrix[0]) -def _verify_matrix_sizes(matrix_a: List[list], matrix_b: List[list]) -> Tuple[list]: +def _verify_matrix_sizes(matrix_a: list[list], matrix_b: list[list]) -> tuple[list]: shape = _shape(matrix_a) + _shape(matrix_b) if shape[0] != shape[3] or shape[1] != shape[2]: raise ValueError( diff --git a/matrix/searching_in_sorted_matrix.py b/matrix/searching_in_sorted_matrix.py index 470fc01dfb8f..ca6263a32f50 100644 --- a/matrix/searching_in_sorted_matrix.py +++ b/matrix/searching_in_sorted_matrix.py @@ -1,21 +1,23 @@ -from typing import List, Union +from __future__ import annotations + +from typing import Union def search_in_a_sorted_matrix( - mat: List[list], m: int, n: int, key: Union[int, float] + mat: list[list], m: int, n: int, key: Union[int, float] ) -> None: """ - >>> search_in_a_sorted_matrix(\ - [[2, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 5) + >>> search_in_a_sorted_matrix( + ... [[2, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 5) Key 5 found at row- 1 column- 2 - >>> search_in_a_sorted_matrix(\ - [[2, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 21) + >>> search_in_a_sorted_matrix( + ... [[2, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 21) Key 21 not found - >>> search_in_a_sorted_matrix(\ - [[2.1, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 2.1) + >>> search_in_a_sorted_matrix( + ... [[2.1, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 2.1) Key 2.1 found at row- 1 column- 1 - >>> search_in_a_sorted_matrix(\ - [[2.1, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 2.2) + >>> search_in_a_sorted_matrix( + ... [[2.1, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 2.2) Key 2.2 not found """ i, j = m - 1, 0 diff --git a/other/dijkstra_bankers_algorithm.py b/other/dijkstra_bankers_algorithm.py index 405c10b88495..be7bceba125d 100644 --- a/other/dijkstra_bankers_algorithm.py +++ b/other/dijkstra_bankers_algorithm.py @@ -15,8 +15,9 @@ (https://rosettacode.org/wiki/Banker%27s_algorithm) """ +from __future__ import annotations + import time -from typing import Dict, List import numpy as np @@ -40,9 +41,9 @@ class BankersAlgorithm: def __init__( self, - claim_vector: List[int], - allocated_resources_table: List[List[int]], - maximum_claim_table: List[List[int]], + claim_vector: list[int], + allocated_resources_table: list[list[int]], + maximum_claim_table: list[list[int]], ) -> None: """ :param claim_vector: A nxn/nxm list depicting the amount of each resources @@ -56,7 +57,7 @@ def __init__( self.__allocated_resources_table = allocated_resources_table self.__maximum_claim_table = maximum_claim_table - def __processes_resource_summation(self) -> List[int]: + def __processes_resource_summation(self) -> list[int]: """ Check for allocated resources in line with each resource in the claim vector """ @@ -65,7 +66,7 @@ def __processes_resource_summation(self) -> List[int]: for i in range(len(self.__allocated_resources_table[0])) ] - def __available_resources(self) -> List[int]: + def __available_resources(self) -> list[int]: """ Check for available resources in line with each resource in the claim vector """ @@ -73,7 +74,7 @@ def __available_resources(self) -> List[int]: self.__processes_resource_summation() ) - def __need(self) -> List[List[int]]: + def __need(self) -> list[list[int]]: """ Implement safety checker that calculates the needs by ensuring that max_claim[i][j] - alloc_table[i][j] <= avail[j] @@ -83,7 +84,7 @@ def __need(self) -> List[List[int]]: for i, allocated_resource in enumerate(self.__allocated_resources_table) ] - def __need_index_manager(self) -> Dict[int, List[int]]: + def __need_index_manager(self) -> dict[int, list[int]]: """ This function builds an index control dictionary to track original ids/indices of processes when altered during execution of method "main" diff --git a/other/markov_chain.py b/other/markov_chain.py index 9b13fa515709..b93c408cd288 100644 --- a/other/markov_chain.py +++ b/other/markov_chain.py @@ -1,6 +1,7 @@ +from __future__ import annotations + from collections import Counter from random import random -from typing import Dict, List, Tuple class MarkovChainGraphUndirectedUnweighted: @@ -23,7 +24,7 @@ def add_transition_probability( self.add_node(node2) self.connections[node1][node2] = probability - def get_nodes(self) -> List[str]: + def get_nodes(self) -> list[str]: return list(self.connections) def transition(self, node: str) -> str: @@ -37,8 +38,8 @@ def transition(self, node: str) -> str: def get_transitions( - start: str, transitions: List[Tuple[str, str, float]], steps: int -) -> Dict[str, int]: + start: str, transitions: list[tuple[str, str, float]], steps: int +) -> dict[str, int]: """ Running Markov Chain algorithm and calculating the number of times each node is visited diff --git a/other/triplet_sum.py b/other/triplet_sum.py index 25fed5d54579..0e78bb52bb72 100644 --- a/other/triplet_sum.py +++ b/other/triplet_sum.py @@ -3,13 +3,14 @@ we are required to find a triplet from the array such that it's sum is equal to the target. """ +from __future__ import annotations + from itertools import permutations from random import randint from timeit import repeat -from typing import List, Tuple -def make_dataset() -> Tuple[List[int], int]: +def make_dataset() -> tuple[list[int], int]: arr = [randint(-1000, 1000) for i in range(10)] r = randint(-5000, 5000) return (arr, r) @@ -18,7 +19,7 @@ def make_dataset() -> Tuple[List[int], int]: dataset = make_dataset() -def triplet_sum1(arr: List[int], target: int) -> Tuple[int, int, int]: +def triplet_sum1(arr: list[int], target: int) -> tuple[int, int, int]: """ Returns a triplet in the array with sum equal to target, else (0, 0, 0). @@ -37,7 +38,7 @@ def triplet_sum1(arr: List[int], target: int) -> Tuple[int, int, int]: return (0, 0, 0) -def triplet_sum2(arr: List[int], target: int) -> Tuple[int, int, int]: +def triplet_sum2(arr: list[int], target: int) -> tuple[int, int, int]: """ Returns a triplet in the array with sum equal to target, else (0, 0, 0). @@ -64,7 +65,7 @@ def triplet_sum2(arr: List[int], target: int) -> Tuple[int, int, int]: return (0, 0, 0) -def solution_times() -> Tuple[float, float]: +def solution_times() -> tuple[float, float]: setup_code = """ from __main__ import dataset, triplet_sum1, triplet_sum2 """ diff --git a/project_euler/problem_35/sol1.py b/project_euler/problem_35/sol1.py index c47eb7d82f54..5f023c56ae50 100644 --- a/project_euler/problem_35/sol1.py +++ b/project_euler/problem_35/sol1.py @@ -10,7 +10,7 @@ we will rule out the numbers which contain an even digit. After this we will generate each circular combination of the number and check if all are prime. """ -from typing import List +from __future__ import annotations seive = [True] * 1000001 i = 2 @@ -47,7 +47,7 @@ def contains_an_even_digit(n: int) -> bool: return any(digit in "02468" for digit in str(n)) -def find_circular_primes(limit: int = 1000000) -> List[int]: +def find_circular_primes(limit: int = 1000000) -> list[int]: """ Return circular primes below limit. >>> len(find_circular_primes(100)) diff --git a/project_euler/problem_37/sol1.py b/project_euler/problem_37/sol1.py index c01d64d83fbe..e3aec5a844fe 100644 --- a/project_euler/problem_37/sol1.py +++ b/project_euler/problem_37/sol1.py @@ -9,8 +9,7 @@ NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes. """ - -from typing import List +from __future__ import annotations seive = [True] * 1000001 seive[1] = False @@ -36,7 +35,7 @@ def is_prime(n: int) -> bool: return seive[n] -def list_truncated_nums(n: int) -> List[int]: +def list_truncated_nums(n: int) -> list[int]: """ Returns a list of all left and right truncated numbers of n >>> list_truncated_nums(927628) @@ -71,7 +70,7 @@ def validate(n: int) -> bool: return True -def compute_truncated_primes(count: int = 11) -> List[int]: +def compute_truncated_primes(count: int = 11) -> list[int]: """ Returns the list of truncated primes >>> compute_truncated_primes(11) diff --git a/project_euler/problem_39/sol1.py b/project_euler/problem_39/sol1.py index b0a5d5188fed..79fa309f01c5 100644 --- a/project_euler/problem_39/sol1.py +++ b/project_euler/problem_39/sol1.py @@ -6,11 +6,12 @@ For which value of p ≤ 1000, is the number of solutions maximised? """ +from __future__ import annotations + from collections import Counter -from typing import Dict -def pythagorean_triple(max_perimeter: int) -> Dict: +def pythagorean_triple(max_perimeter: int) -> dict: """ Returns a dictionary with keys as the perimeter of a right angled triangle and value as the number of corresponding triplets. diff --git a/project_euler/problem_41/sol1.py b/project_euler/problem_41/sol1.py index 4ed09ccb8565..b4c0d842ae25 100644 --- a/project_euler/problem_41/sol1.py +++ b/project_euler/problem_41/sol1.py @@ -1,6 +1,7 @@ +from __future__ import annotations + from itertools import permutations from math import sqrt -from typing import List """ We shall say that an n-digit number is pandigital if it makes use of all the digits @@ -34,7 +35,7 @@ def is_prime(n: int) -> bool: return True -def compute_pandigital_primes(n: int) -> List[int]: +def compute_pandigital_primes(n: int) -> list[int]: """ Returns a list of all n-digit pandigital primes. >>> compute_pandigital_primes(2) diff --git a/project_euler/problem_46/sol1.py b/project_euler/problem_46/sol1.py index 761e9b8cc7fb..e94e9247d86b 100644 --- a/project_euler/problem_46/sol1.py +++ b/project_euler/problem_46/sol1.py @@ -15,7 +15,7 @@ prime and twice a square? """ -from typing import List +from __future__ import annotations seive = [True] * 100001 i = 2 @@ -43,7 +43,7 @@ def is_prime(n: int) -> bool: odd_composites = [num for num in range(3, len(seive), 2) if not is_prime(num)] -def compute_nums(n: int) -> List[int]: +def compute_nums(n: int) -> list[int]: """ Returns a list of first n odd composite numbers which do not follow the conjecture. diff --git a/project_euler/problem_54/sol1.py b/project_euler/problem_54/sol1.py index 3275fe6cd483..d36d3702d7c8 100644 --- a/project_euler/problem_54/sol1.py +++ b/project_euler/problem_54/sol1.py @@ -40,7 +40,7 @@ https://www.codewars.com/kata/ranking-poker-hands https://www.codewars.com/kata/sortable-poker-hands """ -from typing import List, Set, Tuple +from __future__ import annotations class PokerHand(object): @@ -310,7 +310,7 @@ def _is_same_kind(self) -> int: self._second_pair = second return kind - def _internal_state(self) -> Tuple[List[int], Set[str]]: + def _internal_state(self) -> tuple[list[int], set[str]]: # Internal representation of hand as a list of card values and # a set of card suit trans: dict = {"T": "10", "J": "11", "Q": "12", "K": "13", "A": "14"} diff --git a/scheduling/first_come_first_served.py b/scheduling/first_come_first_served.py index b51fc9fe0c04..c5f61720f97e 100644 --- a/scheduling/first_come_first_served.py +++ b/scheduling/first_come_first_served.py @@ -2,10 +2,10 @@ # In this Algorithm we just care about the order that the processes arrived # without carring about their duration time # https://en.wikipedia.org/wiki/Scheduling_(computing)#First_come,_first_served -from typing import List +from __future__ import annotations -def calculate_waiting_times(duration_times: List[int]) -> List[int]: +def calculate_waiting_times(duration_times: list[int]) -> list[int]: """ This function calculates the waiting time of some processes that have a specified duration time. @@ -24,8 +24,8 @@ def calculate_waiting_times(duration_times: List[int]) -> List[int]: def calculate_turnaround_times( - duration_times: List[int], waiting_times: List[int] -) -> List[int]: + duration_times: list[int], waiting_times: list[int] +) -> list[int]: """ This function calculates the turnaround time of some processes. Return: The time difference between the completion time and the @@ -44,7 +44,7 @@ def calculate_turnaround_times( ] -def calculate_average_turnaround_time(turnaround_times: List[int]) -> float: +def calculate_average_turnaround_time(turnaround_times: list[int]) -> float: """ This function calculates the average of the turnaround times Return: The average of the turnaround times. @@ -58,7 +58,7 @@ def calculate_average_turnaround_time(turnaround_times: List[int]) -> float: return sum(turnaround_times) / len(turnaround_times) -def calculate_average_waiting_time(waiting_times: List[int]) -> float: +def calculate_average_waiting_time(waiting_times: list[int]) -> float: """ This function calculates the average of the waiting times Return: The average of the waiting times. diff --git a/scheduling/round_robin.py b/scheduling/round_robin.py index 4a79301c1816..e8d54dd9a553 100755 --- a/scheduling/round_robin.py +++ b/scheduling/round_robin.py @@ -3,11 +3,12 @@ In Round Robin each process is assigned a fixed time slot in a cyclic way. https://en.wikipedia.org/wiki/Round-robin_scheduling """ +from __future__ import annotations + from statistics import mean -from typing import List -def calculate_waiting_times(burst_times: List[int]) -> List[int]: +def calculate_waiting_times(burst_times: list[int]) -> list[int]: """ Calculate the waiting times of a list of processes that have a specified duration. @@ -40,8 +41,8 @@ def calculate_waiting_times(burst_times: List[int]) -> List[int]: def calculate_turn_around_times( - burst_times: List[int], waiting_times: List[int] -) -> List[int]: + burst_times: list[int], waiting_times: list[int] +) -> list[int]: """ >>> calculate_turn_around_times([1, 2, 3, 4], [0, 1, 3]) [1, 3, 6] diff --git a/scheduling/shortest_job_first.py b/scheduling/shortest_job_first.py index ecb6e01fdfe6..f9e2ad975627 100644 --- a/scheduling/shortest_job_first.py +++ b/scheduling/shortest_job_first.py @@ -3,14 +3,14 @@ Please note arrival time and burst Please use spaces to separate times entered. """ -from typing import List +from __future__ import annotations import pandas as pd def calculate_waitingtime( - arrival_time: List[int], burst_time: List[int], no_of_processes: int -) -> List[int]: + arrival_time: list[int], burst_time: list[int], no_of_processes: int +) -> list[int]: """ Calculate the waiting time of each processes Return: list of waiting times. @@ -72,8 +72,8 @@ def calculate_waitingtime( def calculate_turnaroundtime( - burst_time: List[int], no_of_processes: int, waiting_time: List[int] -) -> List[int]: + burst_time: list[int], no_of_processes: int, waiting_time: list[int] +) -> list[int]: """ Calculate the turn around time of each Processes Return: list of turn around times. @@ -91,7 +91,7 @@ def calculate_turnaroundtime( def calculate_average_times( - waiting_time: List[int], turn_around_time: List[int], no_of_processes: int + waiting_time: list[int], turn_around_time: list[int], no_of_processes: int ): """ This function calculates the average of the waiting & turnaround times diff --git a/searches/double_linear_search.py b/searches/double_linear_search.py index 6056f00fc2bb..d9dad3c685b6 100644 --- a/searches/double_linear_search.py +++ b/searches/double_linear_search.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def double_linear_search(array: List[int], search_item: int) -> int: +def double_linear_search(array: list[int], search_item: int) -> int: """ Iterate through the array from both sides to find the index of search_item. diff --git a/searches/simple_binary_search.py b/searches/simple_binary_search.py index b6215312fb2d..8495dda8d518 100644 --- a/searches/simple_binary_search.py +++ b/searches/simple_binary_search.py @@ -7,10 +7,10 @@ For manual testing run: python3 simple_binary_search.py """ -from typing import List +from __future__ import annotations -def binary_search(a_list: List[int], item: int) -> bool: +def binary_search(a_list: list[int], item: int) -> bool: """ >>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42] >>> print(binary_search(test_list, 3)) diff --git a/sorts/iterative_merge_sort.py b/sorts/iterative_merge_sort.py index e6e1513393e0..5ee0badab9e6 100644 --- a/sorts/iterative_merge_sort.py +++ b/sorts/iterative_merge_sort.py @@ -9,10 +9,10 @@ python3 iterative_merge_sort.py """ -from typing import List +from __future__ import annotations -def merge(input_list: List, low: int, mid: int, high: int) -> List: +def merge(input_list: list, low: int, mid: int, high: int) -> list: """ sorting left-half and right-half individually then merging them into result @@ -26,7 +26,7 @@ def merge(input_list: List, low: int, mid: int, high: int) -> List: # iteration over the unsorted list -def iter_merge_sort(input_list: List) -> List: +def iter_merge_sort(input_list: list) -> list: """ Return a sorted copy of the input list diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 339851699525..fb71d84a3c14 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -11,10 +11,10 @@ python3 merge_insertion_sort.py """ -from typing import List +from __future__ import annotations -def merge_insertion_sort(collection: List[int]) -> List[int]: +def merge_insertion_sort(collection: list[int]) -> list[int]: """Pure implementation of merge-insertion sort algorithm in Python :param collection: some mutable ordered collection with heterogeneous diff --git a/sorts/radix_sort.py b/sorts/radix_sort.py index 0ddf996cf1ee..7942462ea10d 100644 --- a/sorts/radix_sort.py +++ b/sorts/radix_sort.py @@ -1,7 +1,7 @@ -from typing import List +from __future__ import annotations -def radix_sort(list_of_ints: List[int]) -> List[int]: +def radix_sort(list_of_ints: list[int]) -> list[int]: """ radix_sort(range(15)) == sorted(range(15)) True diff --git a/sorts/recursive_insertion_sort.py b/sorts/recursive_insertion_sort.py index 5b14c2a6c139..66dd08157df1 100644 --- a/sorts/recursive_insertion_sort.py +++ b/sorts/recursive_insertion_sort.py @@ -2,10 +2,10 @@ A recursive implementation of the insertion sort algorithm """ -from typing import List +from __future__ import annotations -def rec_insertion_sort(collection: List, n: int): +def rec_insertion_sort(collection: list, n: int): """ Given a collection of numbers and its length, sorts the collections in ascending order @@ -36,7 +36,7 @@ def rec_insertion_sort(collection: List, n: int): rec_insertion_sort(collection, n - 1) -def insert_next(collection: List, index: int): +def insert_next(collection: list, index: int): """ Inserts the '(index-1)th' element into place diff --git a/traversals/binary_tree_traversals.py b/traversals/binary_tree_traversals.py index 50cdd5af72d3..cb471ba55bac 100644 --- a/traversals/binary_tree_traversals.py +++ b/traversals/binary_tree_traversals.py @@ -3,8 +3,9 @@ """ This is pure Python implementation of tree traversal algorithms """ +from __future__ import annotations + import queue -from typing import List class TreeNode: diff --git a/web_programming/fetch_jobs.py b/web_programming/fetch_jobs.py index 888f41294974..bb2171e1f0ee 100644 --- a/web_programming/fetch_jobs.py +++ b/web_programming/fetch_jobs.py @@ -1,7 +1,9 @@ """ Scraping jobs given job title and location from indeed website """ -from typing import Generator, Tuple +from __future__ import annotations + +from typing import Generator import requests from bs4 import BeautifulSoup @@ -9,7 +11,7 @@ url = "https://www.indeed.co.in/jobs?q=mobile+app+development&l=" -def fetch_jobs(location: str = "mumbai") -> Generator[Tuple[str, str], None, None]: +def fetch_jobs(location: str = "mumbai") -> Generator[tuple[str, str], None, None]: soup = BeautifulSoup(requests.get(url + location).content, "html.parser") # This attribute finds out all the specifics listed in a job for job in soup.find_all("div", attrs={"data-tn-component": "organicJob"}): diff --git a/web_programming/get_imdb_top_250_movies_csv.py b/web_programming/get_imdb_top_250_movies_csv.py index 811c21fb00e4..e54b076ebd94 100644 --- a/web_programming/get_imdb_top_250_movies_csv.py +++ b/web_programming/get_imdb_top_250_movies_csv.py @@ -1,11 +1,12 @@ +from __future__ import annotations + import csv -from typing import Dict import requests from bs4 import BeautifulSoup -def get_imdb_top_250_movies(url: str = "") -> Dict[str, float]: +def get_imdb_top_250_movies(url: str = "") -> dict[str, float]: url = url or "https://www.imdb.com/chart/top/?ref_=nv_mv_250" soup = BeautifulSoup(requests.get(url).text, "html.parser") titles = soup.find_all("td", attrs="titleColumn") From de3b68dde81e9d9c4058cc40d7a02c3eda095e91 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 23 Sep 2020 23:50:21 +0500 Subject: [PATCH 43/55] added main method for calling on lunch --- backtracking/minimax.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index fd7abad12b61..f0924b822e2b 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,5 @@ from typing import List +import math """ Minimax helps to achieve maximum score in a game by checking all possible moves depth is current depth in game tree. @@ -56,7 +57,15 @@ def minimax(depth: int, node_index: int, is_max: bool, ) +def main(): + scores = [90, 23, 6, 33, 21, 65, 123, 34423] + height = math.log(len(scores), 2) + print("Optimal value : ", end="") + print(minimax(0, 0, True, scores, height)) + + if __name__ == "__main__": import doctest doctest.testmod() + main() From 5f9be0a6131d2e78b697be6304077e9a69932d1e Mon Sep 17 00:00:00 2001 From: spamegg <4255997+spamegg1@users.noreply.github.com> Date: Wed, 23 Sep 2020 22:55:51 +0300 Subject: [PATCH 44/55] Add Python type hints and doctests to other/two_sum.py (#2467) * Add Python type hints and doctests to other/two_sum.py #2465 * Update other/two_sum.py Co-authored-by: Christian Clauss * Update other/two_sum.py Co-authored-by: Christian Clauss * Update two_sum.py Co-authored-by: Christian Clauss --- other/two_sum.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/other/two_sum.py b/other/two_sum.py index 8ac7a18ba9a4..5209acbc7e44 100644 --- a/other/two_sum.py +++ b/other/two_sum.py @@ -11,21 +11,37 @@ Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. """ +from __future__ import annotations -def twoSum(nums, target): +def two_sum(nums: list[int], target: int) -> list[int]: """ - :type nums: List[int] - :type target: int - :rtype: List[int] + >>> two_sum([2, 7, 11, 15], 9) + [0, 1] + >>> two_sum([15, 2, 11, 7], 13) + [1, 2] + >>> two_sum([2, 7, 11, 15], 17) + [0, 3] + >>> two_sum([7, 15, 11, 2], 18) + [0, 2] + >>> two_sum([2, 7, 11, 15], 26) + [2, 3] + >>> two_sum([2, 7, 11, 15], 8) + [] + >>> two_sum([3 * i for i in range(10)], 19) + [] """ chk_map = {} for index, val in enumerate(nums): compl = target - val if compl in chk_map: - indices = [chk_map[compl], index] - print(indices) - return [indices] - else: - chk_map[val] = index - return False + return [chk_map[compl], index] + chk_map[val] = index + return [] + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + print(f"{two_sum([2, 7, 11, 15], 9) = }") From 4a3b8d682e2e296761d2fb866418e57fe5ff4b42 Mon Sep 17 00:00:00 2001 From: Vivek Date: Thu, 24 Sep 2020 13:00:22 +0530 Subject: [PATCH 45/55] Added binary_xor_operator.py and binary_and_operator.py (#2433) * Added binary_and_operator.py & binary_xor_operator.py * Updated binary_and_operator.py * Updated binary_xor_operator.py * Updated binary_xor_operator.py --- bit_manipulation/binary_and_operator.py | 51 +++++++++++++++++++++++++ bit_manipulation/binary_xor_operator.py | 51 +++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 bit_manipulation/binary_and_operator.py create mode 100644 bit_manipulation/binary_xor_operator.py diff --git a/bit_manipulation/binary_and_operator.py b/bit_manipulation/binary_and_operator.py new file mode 100644 index 000000000000..e5dffe3e31d2 --- /dev/null +++ b/bit_manipulation/binary_and_operator.py @@ -0,0 +1,51 @@ +# https://www.tutorialspoint.com/python3/bitwise_operators_example.htm + +def binary_and(a: int, b: int): + """ + Take in 2 integers, convert them to binary, + return a binary number that is the + result of a binary and operation on the integers provided. + + >>> binary_and(25, 32) + '0b000000' + >>> binary_and(37, 50) + '0b100000' + >>> binary_and(21, 30) + '0b10100' + >>> binary_and(58, 73) + '0b0001000' + >>> binary_and(0, 255) + '0b00000000' + >>> binary_and(256, 256) + '0b100000000' + >>> binary_and(0, -1) + Traceback (most recent call last): + ... + ValueError: the value of both input must be positive + >>> binary_and(0, 1.1) + Traceback (most recent call last): + ... + TypeError: 'float' object cannot be interpreted as an integer + >>> binary_and("0", "1") + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + """ + if a < 0 or b < 0: + raise ValueError("the value of both input must be positive") + + a_binary = str(bin(a))[2:] # remove the leading "0b" + b_binary = str(bin(b))[2:] # remove the leading "0b" + + max_len = max(len(a_binary), len(b_binary)) + + return "0b" + "".join( + str(int(char_a == "1" and char_b == "1")) + for char_a, char_b in zip(a_binary.zfill(max_len), b_binary.zfill(max_len)) + ) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/bit_manipulation/binary_xor_operator.py b/bit_manipulation/binary_xor_operator.py new file mode 100644 index 000000000000..32a8f272116e --- /dev/null +++ b/bit_manipulation/binary_xor_operator.py @@ -0,0 +1,51 @@ +# https://www.tutorialspoint.com/python3/bitwise_operators_example.htm + +def binary_xor(a: int, b: int): + """ + Take in 2 integers, convert them to binary, + return a binary number that is the + result of a binary xor operation on the integers provided. + + >>> binary_xor(25, 32) + '0b111001' + >>> binary_xor(37, 50) + '0b010111' + >>> binary_xor(21, 30) + '0b01011' + >>> binary_xor(58, 73) + '0b1110011' + >>> binary_xor(0, 255) + '0b11111111' + >>> binary_xor(256, 256) + '0b000000000' + >>> binary_xor(0, -1) + Traceback (most recent call last): + ... + ValueError: the value of both input must be positive + >>> binary_xor(0, 1.1) + Traceback (most recent call last): + ... + TypeError: 'float' object cannot be interpreted as an integer + >>> binary_xor("0", "1") + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + """ + if a < 0 or b < 0: + raise ValueError("the value of both input must be positive") + + a_binary = str(bin(a))[2:] # remove the leading "0b" + b_binary = str(bin(b))[2:] # remove the leading "0b" + + max_len = max(len(a_binary), len(b_binary)) + + return "0b" + "".join( + str(int(char_a != char_b)) + for char_a, char_b in zip(a_binary.zfill(max_len), b_binary.zfill(max_len)) + ) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From 902fe1c9070fa5b1e29d33e3742e3a871f07170a Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Thu, 24 Sep 2020 19:12:52 +0800 Subject: [PATCH 46/55] Fixed reverse words algorithm (#2469) * updated reversed words * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- bit_manipulation/binary_and_operator.py | 1 + bit_manipulation/binary_xor_operator.py | 1 + strings/reverse_words.py | 17 +++++++---------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/bit_manipulation/binary_and_operator.py b/bit_manipulation/binary_and_operator.py index e5dffe3e31d2..f1b910f8cc9b 100644 --- a/bit_manipulation/binary_and_operator.py +++ b/bit_manipulation/binary_and_operator.py @@ -1,5 +1,6 @@ # https://www.tutorialspoint.com/python3/bitwise_operators_example.htm + def binary_and(a: int, b: int): """ Take in 2 integers, convert them to binary, diff --git a/bit_manipulation/binary_xor_operator.py b/bit_manipulation/binary_xor_operator.py index 32a8f272116e..0edf2ba6606d 100644 --- a/bit_manipulation/binary_xor_operator.py +++ b/bit_manipulation/binary_xor_operator.py @@ -1,5 +1,6 @@ # https://www.tutorialspoint.com/python3/bitwise_operators_example.htm + def binary_xor(a: int, b: int): """ Take in 2 integers, convert them to binary, diff --git a/strings/reverse_words.py b/strings/reverse_words.py index 8ab060fe1d24..504c1c2089dd 100644 --- a/strings/reverse_words.py +++ b/strings/reverse_words.py @@ -1,18 +1,15 @@ -# Created by sarathkaul on 18/11/19 -# Edited by farnswj1 on 4/4/20 - - def reverse_words(input_str: str) -> str: """ Reverses words in a given string - >>> sentence = "I love Python" - >>> reverse_words(sentence) == " ".join(sentence.split()[::-1]) - True - >>> reverse_words(sentence) + >>> reverse_words("I love Python") 'Python love I' + >>> reverse_words("I Love Python") + 'Python Love I' """ - return " ".join(reversed(input_str.split(" "))) + return " ".join(input_str.split()[::-1]) if __name__ == "__main__": - print(reverse_words("INPUT STRING")) + import doctest + + doctest.testmod() From 3a275caf0122474e42f9ac68e57618607bde3b96 Mon Sep 17 00:00:00 2001 From: Du Yuanchao Date: Thu, 24 Sep 2020 19:14:52 +0800 Subject: [PATCH 47/55] Fixed remove duplicate (#2470) * fixed remove duplicate * fixup! Format Python code with psf/black push Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- strings/remove_duplicate.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/strings/remove_duplicate.py b/strings/remove_duplicate.py index 6357050ac17d..5ab0e9962752 100644 --- a/strings/remove_duplicate.py +++ b/strings/remove_duplicate.py @@ -1,14 +1,15 @@ -""" Created by sarathkaul on 14/11/19 """ - - def remove_duplicates(sentence: str) -> str: """ - Reomove duplicates from sentence + Remove duplicates from sentence >>> remove_duplicates("Python is great and Java is also great") 'Java Python also and great is' + >>> remove_duplicates("Python is great and Java is also great") + 'Java Python also and great is' """ - return " ".join(sorted(set(sentence.split(" ")))) + return " ".join(sorted(set(sentence.split()))) if __name__ == "__main__": - print(remove_duplicates("INPUT_SENTENCE")) + import doctest + + doctest.testmod() From 08eb1efafe01c89f83914d8792ef0dc849f92360 Mon Sep 17 00:00:00 2001 From: Dhruv Date: Thu, 24 Sep 2020 18:46:55 +0530 Subject: [PATCH 48/55] Add solution() for problem 54 of Project Euler (#2472) * Add solution() for problem 54 of Project Euler * Add type hints for solution() function --- project_euler/problem_54/sol1.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/project_euler/problem_54/sol1.py b/project_euler/problem_54/sol1.py index d36d3702d7c8..4d75271784de 100644 --- a/project_euler/problem_54/sol1.py +++ b/project_euler/problem_54/sol1.py @@ -42,6 +42,8 @@ """ from __future__ import annotations +import os + class PokerHand(object): """Create an object representing a Poker Hand based on an input of a @@ -356,3 +358,24 @@ def __ge__(self, other): def __hash__(self): return object.__hash__(self) + + +def solution() -> int: + # Solution for problem number 54 from Project Euler + # Input from poker_hands.txt file + answer = 0 + script_dir = os.path.abspath(os.path.dirname(__file__)) + poker_hands = os.path.join(script_dir, "poker_hands.txt") + with open(poker_hands, "r") as file_hand: + for line in file_hand: + player_hand = line[:14].strip() + opponent_hand = line[15:].strip() + player, opponent = PokerHand(player_hand), PokerHand(opponent_hand) + output = player.compare_with(opponent) + if output == "Win": + answer += 1 + return answer + + +if __name__ == "__main__": + solution() From d3c3f90778e1430fe0358118d91138516aa00793 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Sun, 16 Aug 2020 00:48:27 +0500 Subject: [PATCH 49/55] added type hints for backtracking/minimax.py --- backtracking/minimax.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 4cec0e403ddf..4019dd15aef0 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,5 @@ import math +from typing import List """ Minimax helps to achieve maximum score in a game by checking all possible moves depth is current depth in game tree. @@ -9,24 +10,24 @@ """ -def minimax(Depth, nodeIndex, isMax, scores, height): +def minimax(depth: int, node_index: int, is_max: bool, + scores: List[int], height: float) -> int: + if depth == height: + return scores[node_index] - if Depth == height: - return scores[nodeIndex] - - if isMax: + if is_max: return max( - minimax(Depth + 1, nodeIndex * 2, False, scores, height), - minimax(Depth + 1, nodeIndex * 2 + 1, False, scores, height), + minimax(depth + 1, node_index * 2, False, scores, height), + minimax(depth + 1, node_index * 2 + 1, False, scores, height), ) + return min( - minimax(Depth + 1, nodeIndex * 2, True, scores, height), - minimax(Depth + 1, nodeIndex * 2 + 1, True, scores, height), + minimax(depth + 1, node_index * 2, True, scores, height), + minimax(depth + 1, node_index * 2 + 1, True, scores, height), ) if __name__ == "__main__": - scores = [90, 23, 6, 33, 21, 65, 123, 34423] height = math.log(len(scores), 2) From 584d1dacc9f550750906477387c0aea575604f6a Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 26 Aug 2020 23:03:25 +0500 Subject: [PATCH 50/55] added some simple test cases --- backtracking/minimax.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 4019dd15aef0..f9611541e426 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -12,6 +12,35 @@ def minimax(depth: int, node_index: int, is_max: bool, scores: List[int], height: float) -> int: + """ + >>> scores = [90, 23, 6, 33, 21, 65, 123, 34423] + >>> height = math.log(len(scores), 2) + >>> minimax(0, 0, True, scores, height) + 65 + >>> minimax(-1, 0, True, scores, height) + Traceback (most recent call last): + ... + ValueError: Depth cannot be less than 0 + >>> minimax(0, 0, True, [], 2) + Traceback (most recent call last): + ... + ValueError: Scores cannot be empty + >>> scores = [3, 5, 2, 9, 12, 5, 23, 23] + >>> height = math.log(len(scores), 2) + >>> minimax(0, 0, True, scores, height) + 12 + >>> minimax('1', 2, True, [], 2 ) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + """ + + if depth < 0: + raise ValueError("Depth cannot be less than 0") + + if len(scores) == 0: + raise ValueError("Scores cannot be empty") + if depth == height: return scores[node_index] @@ -28,8 +57,6 @@ def minimax(depth: int, node_index: int, is_max: bool, if __name__ == "__main__": - scores = [90, 23, 6, 33, 21, 65, 123, 34423] - height = math.log(len(scores), 2) + import doctest - print("Optimal value : ", end="") - print(minimax(0, 0, True, scores, height)) + doctest.testmod() From 8e3c12f603e72e8fba05d0c7d67e3dcccc0d4777 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 26 Aug 2020 23:10:41 +0500 Subject: [PATCH 51/55] flake fix --- backtracking/minimax.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index f9611541e426..64c05ebf1d6c 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,3 @@ -import math from typing import List """ Minimax helps to achieve maximum score in a game by checking all possible moves From bb84f979ef561a5ad64faeb552da0a1319ead616 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 26 Aug 2020 23:23:31 +0500 Subject: [PATCH 52/55] fixes doctests --- backtracking/minimax.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 64c05ebf1d6c..fd7abad12b61 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -12,6 +12,7 @@ def minimax(depth: int, node_index: int, is_max: bool, scores: List[int], height: float) -> int: """ + >>> import math >>> scores = [90, 23, 6, 33, 21, 65, 123, 34423] >>> height = math.log(len(scores), 2) >>> minimax(0, 0, True, scores, height) From 549c7980d4a7c4a8f4956675c38599347942601f Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Wed, 23 Sep 2020 23:50:21 +0500 Subject: [PATCH 53/55] added main method for calling on lunch --- backtracking/minimax.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index fd7abad12b61..f0924b822e2b 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,5 @@ from typing import List +import math """ Minimax helps to achieve maximum score in a game by checking all possible moves depth is current depth in game tree. @@ -56,7 +57,15 @@ def minimax(depth: int, node_index: int, is_max: bool, ) +def main(): + scores = [90, 23, 6, 33, 21, 65, 123, 34423] + height = math.log(len(scores), 2) + print("Optimal value : ", end="") + print(minimax(0, 0, True, scores, height)) + + if __name__ == "__main__": import doctest doctest.testmod() + main() From b006adf1ea36f6c6d65b5e8feeecfde1e586d692 Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Thu, 24 Sep 2020 19:13:36 +0500 Subject: [PATCH 54/55] prepare for python 3.9 --- backtracking/minimax.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index f0924b822e2b..28ae42c9a91d 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,4 +1,4 @@ -from typing import List +from __future__ import annotations import math """ Minimax helps to achieve maximum score in a game by checking all possible moves From 1338305f682be88373a0bff2d6bfad7a2885ba5a Mon Sep 17 00:00:00 2001 From: Abdujabbar Mirkhalikov Date: Thu, 24 Sep 2020 19:20:47 +0500 Subject: [PATCH 55/55] fix imports --- backtracking/minimax.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backtracking/minimax.py b/backtracking/minimax.py index 28ae42c9a91d..531d04362200 100644 --- a/backtracking/minimax.py +++ b/backtracking/minimax.py @@ -1,5 +1,7 @@ from __future__ import annotations import math +from typing import List + """ Minimax helps to achieve maximum score in a game by checking all possible moves depth is current depth in game tree.