import sys
import unittest
from dataclasses import dataclass
from typing import *
sys.setrecursionlimit(10**6)
## linked lists are an example of mixed compound data:
LinkedList = Union['LLNode',None]
@dataclass(frozen=True)
class LLNode:
first : Any
rest : LinkedList
# examples of data
l1 = None
l2 = LLNode(3, None)
l3 = LLNode("banana", LLNode(14, None))
l4 = LLNode(None, LLNode("whisper", LLNode(143, None)))
# return the length of the linked list
def ll_len(ll : LinkedList) -> int:
match ll:
case None:
return 0
case LLNode(f,r):
return 1 + ll_len(r)
# does the list contain the string "banana" ?
def contains_banana(ll : LinkedList) -> bool:
match ll:
case None:
return False
case LLNode(f,r):
return (f == "banana") or contains_banana(r)
# what's the reverse of the list?
def ll_reverse(ll : LinkedList) -> LinkedList:
return ll_reverse_helper(ll,None)
def ll_reverse_helper(ll : LinkedList, accum : LinkedList) -> LinkedList:
match ll:
case None:
return accum
case LLNode(f,r):
return ll_reverse_helper(r,LLNode(f,accum))
def ll_append(ll1 : LinkedList, ll2 : LinkedList) -> LinkedList:
match ll1:
case None:
return ll2
case LLNode(f,r):
return LLNode(f,ll_append(r,ll2))
class MyTests(unittest.TestCase):
def test_len(self):
self.assertEqual(0,ll_len(l1))
self.assertEqual(1,ll_len(l2))
self.assertEqual(2,ll_len(l3))
self.assertEqual(3,ll_len(l4))
def test_contains_banana(self):
self.assertEqual(False,contains_banana(l1))
self.assertEqual(True,contains_banana(l3))
self.assertEqual(False,contains_banana(l4))
def test_reverse(self):
self.assertEqual(l1,ll_reverse(l1))
self.assertEqual(l2,ll_reverse(l2))
self.assertEqual(LLNode(14,LLNode("banana",None)),ll_reverse(l3))
self.assertEqual(LLNode(143,LLNode("whisper",LLNode(None,None))),
ll_reverse(l4))
def test_append(self):
self.assertEqual(l1,ll_append(l1,l1))
self.assertEqual(l2,ll_append(l2,l1))
self.assertEqual(LLNode("banana",LLNode(14,LLNode(3,None))),
ll_append(l3,l2))