From 46e56fa6f2e473d1300846b2b96e56f498872400 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 27 Aug 2021 11:45:14 +0200 Subject: [PATCH 1/8] luhn.py: Favor list comprehensions over maps (#4663) * luhn.py: Favor list comprehensions over maps As discussed in CONTRIBUTING.md. * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- hashes/luhn.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/hashes/luhn.py b/hashes/luhn.py index 69e7b4ccf59b..81014120dd80 100644 --- a/hashes/luhn.py +++ b/hashes/luhn.py @@ -4,39 +4,34 @@ def is_luhn(string: str) -> bool: """ - Perform Luhn validation on input string + Perform Luhn validation on an input string Algorithm: * Double every other digit starting from 2nd last digit. * Subtract 9 if number is greater than 9. * Sum the numbers * - >>> test_cases = [79927398710, 79927398711, 79927398712, 79927398713, + >>> test_cases = (79927398710, 79927398711, 79927398712, 79927398713, ... 79927398714, 79927398715, 79927398716, 79927398717, 79927398718, - ... 79927398719] - >>> test_cases = list(map(str, test_cases)) - >>> list(map(is_luhn, test_cases)) + ... 79927398719) + >>> [is_luhn(str(test_case)) for test_case in test_cases] [False, False, False, True, False, False, False, False, False, False] """ check_digit: int _vector: List[str] = list(string) __vector, check_digit = _vector[:-1], int(_vector[-1]) - vector: List[int] = [*map(int, __vector)] + vector: List[int] = [int(digit) for digit in __vector] vector.reverse() - for idx, i in enumerate(vector): - - if idx & 1 == 0: - doubled: int = vector[idx] * 2 + for i, digit in enumerate(vector): + if i & 1 == 0: + doubled: int = digit * 2 if doubled > 9: doubled -= 9 - check_digit += doubled else: - check_digit += i + check_digit += digit - if (check_digit) % 10 == 0: - return True - return False + return check_digit % 10 == 0 if __name__ == "__main__": @@ -44,3 +39,4 @@ def is_luhn(string: str) -> bool: doctest.testmod() assert is_luhn("79927398713") + assert not is_luhn("79927398714") From 8e5c3536c728dd7451ca301dc2d5bfb3f68b0e1a Mon Sep 17 00:00:00 2001 From: arfy slowy Date: Sun, 29 Aug 2021 01:07:10 +0700 Subject: [PATCH 2/8] [fixed] unused variable, standalone running, import doctest module (#4673) * [fixed] unused variable, standalone running, import doctest module information [standalone running](https://www.geeksforgeeks.org/what-does-the-if-__name__-__main__-do/) Signed-off-by: slowy07 * Update other/fischer_yates_shuffle.py Co-authored-by: Christian Clauss * [fixed] change to tuple and fixing callfunction Signed-off-by: slowy07 * Update matrix/spiral_print.py Co-authored-by: Christian Clauss * Update matrix/spiral_print.py Co-authored-by: Christian Clauss * fixing Co-authored-by: Christian Clauss * [fixed] sprial matrix Signed-off-by: slowy07 * Update spiral_print.py * Update spiral_print.py * Update spiral_print.py * Update spiral_print.py Co-authored-by: Christian Clauss --- ...h_fibonacci_using_matrix_exponentiation.py | 3 ++ matrix/spiral_print.py | 34 +++++++++---------- other/fischer_yates_shuffle.py | 6 ++-- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/matrix/nth_fibonacci_using_matrix_exponentiation.py b/matrix/nth_fibonacci_using_matrix_exponentiation.py index 8c39de0f23b6..341a02e1a95d 100644 --- a/matrix/nth_fibonacci_using_matrix_exponentiation.py +++ b/matrix/nth_fibonacci_using_matrix_exponentiation.py @@ -88,4 +88,7 @@ def main(): if __name__ == "__main__": + import doctest + + doctest.testmod() main() diff --git a/matrix/spiral_print.py b/matrix/spiral_print.py index 21dab76156e9..6f699c1ab662 100644 --- a/matrix/spiral_print.py +++ b/matrix/spiral_print.py @@ -4,36 +4,35 @@ Matrix must satisfy below conditions i) matrix should be only one or two dimensional - ii)column of all the row should be equal + ii) number of column of all rows should be equal """ +from collections.abc import Iterable -def checkMatrix(a): + +def check_matrix(matrix): # must be - if type(a) == list and len(a) > 0: - if type(a[0]) == list: - prevLen = 0 - for i in a: - if prevLen == 0: - prevLen = len(i) - result = True - elif prevLen == len(i): + if matrix and isinstance(matrix, Iterable): + if isinstance(matrix[0], Iterable): + prev_len = 0 + for row in matrix: + if prev_len == 0: + prev_len = len(row) result = True else: - result = False + result = prev_len == len(row) else: result = True else: result = False + return result def spiralPrint(a): - - if checkMatrix(a) and len(a) > 0: - + if check_matrix(a) and len(a) > 0: matRow = len(a) - if type(a[0]) == list: + if isinstance(a[0], Iterable): matCol = len(a[0]) else: for dat in a: @@ -64,5 +63,6 @@ def spiralPrint(a): # driver code -a = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] -spiralPrint(a) +if __name__ == "__main__": + a = ([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]) + spiralPrint(a) diff --git a/other/fischer_yates_shuffle.py b/other/fischer_yates_shuffle.py index 6eec738c02e1..035fcb482380 100644 --- a/other/fischer_yates_shuffle.py +++ b/other/fischer_yates_shuffle.py @@ -8,8 +8,8 @@ import random -def FYshuffle(list): - for i in range(len(list)): +def fisher_yates_shuffle(data: list) -> list: + for _ in range(len(list)): a = random.randint(0, len(list) - 1) b = random.randint(0, len(list) - 1) list[a], list[b] = list[b], list[a] @@ -21,4 +21,4 @@ def FYshuffle(list): strings = ["python", "says", "hello", "!"] print("Fisher-Yates Shuffle:") print("List", integers, strings) - print("FY Shuffle", FYshuffle(integers), FYshuffle(strings)) + print("FY Shuffle", fisher_yates_shuffle(integers), fisher_yates_shuffle(strings)) From 3acca3d1d188f89c6aa0fb4c0139ac62426ea296 Mon Sep 17 00:00:00 2001 From: Aswin Murali Date: Mon, 30 Aug 2021 13:36:59 +0530 Subject: [PATCH 3/8] Fix type annotations for integer_partition.py #4052 (#4689) --- dynamic_programming/integer_partition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dynamic_programming/integer_partition.py b/dynamic_programming/integer_partition.py index 4eb06348ce84..8ed2e51bd4bd 100644 --- a/dynamic_programming/integer_partition.py +++ b/dynamic_programming/integer_partition.py @@ -6,8 +6,8 @@ """ -def partition(m): - memo = [[0 for _ in range(m)] for _ in range(m + 1)] +def partition(m: int) -> int: + memo: list[list[int]] = [[0 for _ in range(m)] for _ in range(m + 1)] for i in range(m + 1): memo[i][0] = 1 From 097f83023866d625a38c891a46ce3a70d73d7f63 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 31 Aug 2021 06:56:15 +0200 Subject: [PATCH 4/8] Avoid mutable default arguments (#4691) --- graphs/eulerian_path_and_circuit_for_undirected_graph.py | 4 ++-- graphs/frequent_pattern_graph_miner.py | 4 ++-- maths/radix2_fft.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/graphs/eulerian_path_and_circuit_for_undirected_graph.py b/graphs/eulerian_path_and_circuit_for_undirected_graph.py index 7850933b0201..fa4f73abd86f 100644 --- a/graphs/eulerian_path_and_circuit_for_undirected_graph.py +++ b/graphs/eulerian_path_and_circuit_for_undirected_graph.py @@ -6,8 +6,8 @@ # using dfs for finding eulerian path traversal -def dfs(u, graph, visited_edge, path=[]): - path = path + [u] +def dfs(u, graph, visited_edge, path=None): + path = (path or []) + [u] for v in graph[u]: if visited_edge[u][v] is False: visited_edge[u][v], visited_edge[v][u] = True, True diff --git a/graphs/frequent_pattern_graph_miner.py b/graphs/frequent_pattern_graph_miner.py index 8f344b7bd3ae..548ce3c54ffe 100644 --- a/graphs/frequent_pattern_graph_miner.py +++ b/graphs/frequent_pattern_graph_miner.py @@ -168,11 +168,11 @@ def construct_graph(cluster, nodes): return graph -def myDFS(graph, start, end, path=[]): +def myDFS(graph, start, end, path=None): """ find different DFS walk from given node to Header node """ - path = path + [start] + path = (path or []) + [start] if start == end: paths.append(path) for node in graph[start]: diff --git a/maths/radix2_fft.py b/maths/radix2_fft.py index de87071e5440..9fc9f843e685 100644 --- a/maths/radix2_fft.py +++ b/maths/radix2_fft.py @@ -49,10 +49,10 @@ class FFT: A*B = 0*x^(-0+0j) + 1*x^(2+0j) + 2*x^(3+0j) + 3*x^(8+0j) + 4*x^(6+0j) + 5*x^(8+0j) """ - def __init__(self, polyA=[0], polyB=[0]): + def __init__(self, polyA=None, polyB=None): # Input as list - self.polyA = list(polyA)[:] - self.polyB = list(polyB)[:] + self.polyA = list(polyA or [0])[:] + self.polyB = list(polyB or [0])[:] # Remove leading zero coefficients while self.polyA[-1] == 0: From ef9827166e778879e0bc5847c4bcee6720073657 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 31 Aug 2021 07:56:19 +0200 Subject: [PATCH 5/8] Approve functions used as default arguments (#4699) * Approve functions used as default argumenets * The default value for **seed** is the result of a function call The default value for **seed** is the result of a function call which is not normally recommended and causes flake8-bugbear to raise a B008 error. However, in this case, it is accptable because `LinearCongruentialGenerator.__init__()` will only be called once per instance and it ensures that each instance will generate a unique sequence of numbers. * The default value for **backend** is the result of a function call The default value for **backend** is the result of a function call which is not normally recommended and causes flake8-bugbear to raise a B008 error. However, in this case, it is accptable because `Aer.get_backend()` is called when the function is definition and that same backend is then reused for function calls. * Update linear_congruential_generator.py * Update ripple_adder_classic.py * Update ripple_adder_classic.py * Update ripple_adder_classic.py * Update ripple_adder_classic.py * Update ripple_adder_classic.py --- other/linear_congruential_generator.py | 8 +++++++- quantum/ripple_adder_classic.py | 14 +++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/other/linear_congruential_generator.py b/other/linear_congruential_generator.py index f8b604b8562d..777ee6355b9b 100644 --- a/other/linear_congruential_generator.py +++ b/other/linear_congruential_generator.py @@ -8,7 +8,13 @@ class LinearCongruentialGenerator: A pseudorandom number generator. """ - def __init__(self, multiplier, increment, modulo, seed=int(time())): + # The default value for **seed** is the result of a function call which is not + # normally recommended and causes flake8-bugbear to raise a B008 error. However, + # in this case, it is accptable because `LinearCongruentialGenerator.__init__()` + # will only be called once per instance and it ensures that each instance will + # generate a unique sequence of numbers. + + def __init__(self, multiplier, increment, modulo, seed=int(time())): # noqa: B008 """ These parameters are saved and used when nextNumber() is called. diff --git a/quantum/ripple_adder_classic.py b/quantum/ripple_adder_classic.py index dc0c2103b2e5..8539a62afd52 100644 --- a/quantum/ripple_adder_classic.py +++ b/quantum/ripple_adder_classic.py @@ -53,8 +53,16 @@ def full_adder( circuit.cx(input1_loc, input2_loc) +# The default value for **backend** is the result of a function call which is not +# normally recommended and causes flake8-bugbear to raise a B008 error. However, +# in this case, this is accptable because `Aer.get_backend()` is called when the +# function is defined and that same backend is then reused for all function calls. + + def ripple_adder( - val1: int, val2: int, backend: BaseBackend = Aer.get_backend("qasm_simulator") + val1: int, + val2: int, + backend: BaseBackend = Aer.get_backend("qasm_simulator"), # noqa: B008 ) -> int: """ Quantum Equivalent of a Ripple Adder Circuit @@ -63,7 +71,7 @@ def ripple_adder( Currently only adds 'emulated' Classical Bits but nothing prevents us from doing this with hadamard'd bits :) - Only supports adding +ve Integers + Only supports adding positive integers >>> ripple_adder(3, 4) 7 @@ -99,7 +107,7 @@ def ripple_adder( res = execute(circuit, backend, shots=1).result() # The result is in binary. Convert it back to int - return int(list(res.get_counts().keys())[0], 2) + return int(list(res.get_counts())[0], 2) if __name__ == "__main__": From 757d4fb84f77865fc569aae4129999faf75c970f Mon Sep 17 00:00:00 2001 From: Kiran Hipparagi <49370990+KiranHipparagi@users.noreply.github.com> Date: Wed, 1 Sep 2021 01:36:49 +0530 Subject: [PATCH 6/8] Added Dutch National Flag algorithm #4636 (#4639) * Added Dutch national flag sort Algorithm * Changed file name to dnf_sort.py * Added descriptive name and type hint Added descriptive name and type hint for parameter with doctest for the function dnf_sort. * Added test cases * Added doctest cases * Update sorts/dnf_sort.py * Added doctest for dutch_national_flag_sort sorts/dnf_sort.py * Update sorts/dnf_sort.py * Added doctest for the function dutch_national_flag_sort * update file as per black code formatter * Update dnf_sort.py * Update and rename dnf_sort.py to dutch_national_flag_sort.py Co-authored-by: Christian Clauss --- sorts/dutch_national_flag_sort.py | 100 ++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 sorts/dutch_national_flag_sort.py diff --git a/sorts/dutch_national_flag_sort.py b/sorts/dutch_national_flag_sort.py new file mode 100644 index 000000000000..79afefa73afe --- /dev/null +++ b/sorts/dutch_national_flag_sort.py @@ -0,0 +1,100 @@ +""" +A pure implementation of Dutch national flag (DNF) sort algorithm in Python. +Dutch National Flag algorithm is an algorithm originally designed by Edsger Dijkstra. +It is the most optimal sort for 3 unique values (eg. 0, 1, 2) in a sequence. DNF can +sort a sequence of n size with [0 <= a[i] <= 2] at guaranteed O(n) complexity in a +single pass. + +The flag of the Netherlands consists of three colors: white, red, and blue. +The task is to randomly arrange balls of white, red, and blue in such a way that balls +of the same color are placed together. DNF sorts a sequence of 0, 1, and 2's in linear +time that does not consume any extra space. This algorithm can be implemented only on +a sequence that contains three unique elements. + +1) Time complexity is O(n). +2) Space complexity is O(1). + +More info on: https://en.wikipedia.org/wiki/Dutch_national_flag_problem + +For doctests run following command: +python3 -m doctest -v dutch_national_flag_sort.py + +For manual testing run: +python dnf_sort.py +""" + + +# Python program to sort a sequence containing only 0, 1 and 2 in a single pass. +red = 0 # The first color of the flag. +white = 1 # The second color of the flag. +blue = 2 # The third color of the flag. +colors = (red, white, blue) + + +def dutch_national_flag_sort(sequence: list) -> list: + """ + A pure Python implementation of Dutch National Flag sort algorithm. + :param data: 3 unique integer values (e.g., 0, 1, 2) in an sequence + :return: The same collection in ascending order + + >>> dutch_national_flag_sort([]) + [] + >>> dutch_national_flag_sort([0]) + [0] + >>> dutch_national_flag_sort([2, 1, 0, 0, 1, 2]) + [0, 0, 1, 1, 2, 2] + >>> dutch_national_flag_sort([0, 1, 1, 0, 1, 2, 1, 2, 0, 0, 0, 1]) + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2] + >>> dutch_national_flag_sort("abacab") + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort("Abacab") + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort([3, 2, 3, 1, 3, 0, 3]) + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort([-1, 2, -1, 1, -1, 0, -1]) + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort([1.1, 2, 1.1, 1, 1.1, 0, 1.1]) + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + """ + if not sequence: + return [] + if len(sequence) == 1: + return list(sequence) + low = 0 + high = len(sequence) - 1 + mid = 0 + while mid <= high: + if sequence[mid] == colors[0]: + sequence[low], sequence[mid] = sequence[mid], sequence[low] + low += 1 + mid += 1 + elif sequence[mid] == colors[1]: + mid += 1 + elif sequence[mid] == colors[2]: + sequence[mid], sequence[high] = sequence[high], sequence[mid] + high -= 1 + else: + raise ValueError( + f"The elements inside the sequence must contains only {colors} values" + ) + return sequence + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + user_input = input("Enter numbers separated by commas:\n").strip() + unsorted = [int(item.strip()) for item in user_input.split(",")] + print(f"{dutch_national_flag_sort(unsorted)}") From c1b15a86baabd110347bd4d478d88bc2820824e5 Mon Sep 17 00:00:00 2001 From: imp Date: Fri, 3 Sep 2021 17:49:23 +0800 Subject: [PATCH 7/8] [mypy] Fix type annotations for dynamic programming (#4687) * Fix mypy error for knapsack.py * Fix mypy error for longest_increasing_subsequence * Fix mypy error for fractional_knapsack_2.py --- dynamic_programming/fractional_knapsack_2.py | 19 ++++++------------- dynamic_programming/knapsack.py | 2 +- .../longest_increasing_subsequence.py | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/dynamic_programming/fractional_knapsack_2.py b/dynamic_programming/fractional_knapsack_2.py index cae57738311b..bd776723c146 100644 --- a/dynamic_programming/fractional_knapsack_2.py +++ b/dynamic_programming/fractional_knapsack_2.py @@ -7,7 +7,7 @@ def fractional_knapsack( value: list[int], weight: list[int], capacity: int -) -> tuple[int, list[int]]: +) -> tuple[float, list[float]]: """ >>> value = [1, 3, 5, 7, 9] >>> weight = [0.9, 0.7, 0.5, 0.3, 0.1] @@ -32,8 +32,8 @@ def fractional_knapsack( ratio = [v / w for v, w in zip(value, weight)] index.sort(key=lambda i: ratio[i], reverse=True) - max_value = 0 - fractions = [0] * len(value) + max_value: float = 0 + fractions: list[float] = [0] * len(value) for i in index: if weight[i] <= capacity: fractions[i] = 1 @@ -48,13 +48,6 @@ def fractional_knapsack( if __name__ == "__main__": - n = int(input("Enter number of items: ")) - value = input(f"Enter the values of the {n} item(s) in order: ").split() - value = [int(v) for v in value] - weight = input(f"Enter the positive weights of the {n} item(s) in order: ".split()) - weight = [int(w) for w in weight] - capacity = int(input("Enter maximum weight: ")) - - max_value, fractions = fractional_knapsack(value, weight, capacity) - print("The maximum value of items that can be carried:", max_value) - print("The fractions in which the items should be taken:", fractions) + import doctest + + doctest.testmod() diff --git a/dynamic_programming/knapsack.py b/dynamic_programming/knapsack.py index 69e54c00aa4e..804d7d4f12f5 100644 --- a/dynamic_programming/knapsack.py +++ b/dynamic_programming/knapsack.py @@ -91,7 +91,7 @@ def knapsack_with_example_solution(W: int, wt: list, val: list): ) optimal_val, dp_table = knapsack(W, wt, val, num_items) - example_optional_set = set() + example_optional_set: set = set() _construct_solution(dp_table, wt, num_items, W, example_optional_set) return optimal_val, example_optional_set diff --git a/dynamic_programming/longest_increasing_subsequence.py b/dynamic_programming/longest_increasing_subsequence.py index f5ca8a2b5cdc..a029f9be7d98 100644 --- a/dynamic_programming/longest_increasing_subsequence.py +++ b/dynamic_programming/longest_increasing_subsequence.py @@ -36,7 +36,7 @@ def longest_subsequence(array: list[int]) -> list[int]: # This function is recu pivot = array[0] isFound = False i = 1 - longest_subseq = [] + longest_subseq: list[int] = [] while not isFound and i < array_length: if array[i] < pivot: isFound = True From fbcfbeb837906a6bda3499bc9268e7781965c029 Mon Sep 17 00:00:00 2001 From: Burusothman Date: Mon, 29 Jan 2024 15:55:45 -0500 Subject: [PATCH 8/8] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1e85ed0daa7c..cad0cb116320 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,5 @@ We're on [Gitter](https://gitter.im/TheAlgorithms)! Please join us. ## List of Algorithms See our [directory](DIRECTORY.md). + +Test Edit