Skip to content

Commit

Permalink
feature(C02_P05): add recursive solution to sum lists with improved t…
Browse files Browse the repository at this point in the history
…ests
  • Loading branch information
bindas1 authored and brycedrennan committed Sep 12, 2023
1 parent 6be0972 commit 86e7826
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 61 deletions.
130 changes: 69 additions & 61 deletions chapter_02/p05_sum_lists.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pytest

from chapter_02.linked_list import LinkedList


Expand All @@ -23,34 +25,40 @@ def sum_lists(ll_a, ll_b):
return ll


# this solution does not pass tests
# def sum_lists_followup(ll_a, ll_b):
# # Pad the shorter list with zeros
# if len(ll_a) < len(ll_b):
# for i in range(len(ll_b) - len(ll_a)):
# ll_a.add_to_beginning(0)
# else:
# for i in range(len(ll_a) - len(ll_b)):
# ll_b.add_to_beginning(0)
#
# # Find sum
# n1, n2 = ll_a.head, ll_b.head
# result = 0
# while n1 and n2:
# result = (result * 10) + n1.value + n2.value
# n1 = n1.next
# n2 = n2.next
#
# # Create new linked list
# return NumericLinkedList([int(i) for i in str(result)])
def sum_lists_recursive(ll_a, ll_b) -> "NumericLinkedList":
def sum_lists_helper(ll1_head, ll2_head, remainder, summed_list):
if ll1_head is None and ll2_head is None:
if remainder != 0:
summed_list.add(remainder)
return summed_list
elif ll1_head is None:
result = ll2_head.value + remainder
summed_list.add(result % 10)
return sum_lists_helper(ll1_head, ll2_head.next, result // 10, summed_list)
elif ll2_head is None:
result = ll1_head.value + remainder
summed_list.add(result % 10)
return sum_lists_helper(ll1_head.next, ll2_head, result // 10, summed_list)
else:
result = ll1_head.value + ll2_head.value + remainder
summed_list.add(result % 10)
return sum_lists_helper(
ll1_head.next, ll2_head.next, result // 10, summed_list
)

return sum_lists_helper(ll_a.head, ll_b.head, 0, NumericLinkedList())


class NumericLinkedList(LinkedList):
@classmethod
def generate_from_integer(cls, integer):
integer_parts = [int(c) for c in str(integer)]
integer_parts.reverse()
return cls(integer_parts)
def __init__(self, values=None):
"""handle integer as input"""
if isinstance(values, int):
values = [int(c) for c in str(values)]
values.reverse()
elif isinstance(values, list):
values = values.copy()

super().__init__(values)

def numeric_value(self):
number = 0
Expand All @@ -59,47 +67,47 @@ def numeric_value(self):
return number


test_cases = (
# all values can either be list of integer or integers
# a, b, expected_sum
([7, 1, 6], [5, 9, 2], [2, 1, 9]),
(0, 0, 0),
([], [], 0),
([3, 2, 1], [3, 2, 1], [6, 4, 2]),
(123, 123, 246),
(123, 1, 124),
(1, 123, 124),
)
def test_numeric_linked_list():
ll = NumericLinkedList(321)
assert ll.numeric_value() == 321
assert ll.values() == [1, 2, 3]

testable_functions = (
sum_lists,
# sum_lists_followup
)

testable_functions = (sum_lists, sum_lists_recursive)

def test_numeric_linked_list():
ll = NumericLinkedList.generate_from_integer(321)
assert ll.numeric_value() == 321

@pytest.fixture(params=testable_functions)
def linked_list_summing_function(request):
return request.param


test_cases = (
# inputs can either be list of integer or integers
# a, b, expected_sum
pytest.param([1], [2], [3], id="single_digit"),
pytest.param([0], [0], [0], id="single_digit_zero"),
pytest.param([], [], [], id="empty"),
pytest.param([7, 1, 6], [5, 9, 2], [2, 1, 9], id="3-digit equal length A"),
pytest.param([3, 2, 1], [3, 2, 1], [6, 4, 2], id="3-digit equal length B"),
pytest.param(123, 1, [4, 2, 1], id="3-digit and single digit"),
pytest.param([9, 9, 9], [1], [0, 0, 0, 1], id="carry end"),
pytest.param([9, 9, 9], [9, 9, 9], [8, 9, 9, 1], id="multiple carry"),
)


def test_linked_list_addition():
for f in testable_functions:
for a, b, expected in test_cases:
print(f"{f.__name__}: {a}, {b}, {expected}")
if isinstance(a, int):
ll_a = NumericLinkedList.generate_from_integer(a)
else:
ll_a = NumericLinkedList(a.copy())
@pytest.mark.parametrize("a, b, expected", test_cases)
def test_linked_list_addition(linked_list_summing_function, a, b, expected):
ll_a = NumericLinkedList(a)
ll_b = NumericLinkedList(b)
ll_result = linked_list_summing_function(ll_a, ll_b)
assert ll_result.values() == expected
assert (
ll_a.numeric_value() + ll_b.numeric_value()
== NumericLinkedList(expected).numeric_value()
)

if isinstance(b, int):
ll_b = NumericLinkedList.generate_from_integer(b)
else:
ll_b = NumericLinkedList(b.copy())
result = f(ll_a, ll_b)
if isinstance(expected, int):
assert result.numeric_value() == expected
else:
assert result.values() == expected
ll_result_reverse = linked_list_summing_function(ll_b, ll_a)
assert ll_result_reverse.values() == expected


def example():
Expand All @@ -108,8 +116,8 @@ def example():
print(ll_a)
print(ll_b)
print(sum_lists(ll_a, ll_b))
# print(sum_lists_followup(ll_a, ll_b))


if __name__ == "__main__":
example()
pytest.main(args=[__file__])
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ ignore = C0102,C0111,C0203,C0301,C0302,C0325,C0330,C0412,C0413,C901,E0101,E0202,
[flake8]
max-line-length = 88
extend-ignore = E203,E800,VNE001,VNE002
pytest-parametrize-names-type = csv

0 comments on commit 86e7826

Please sign in to comment.