<jupyter_start><jupyter_text>Ordered ListExtra exercise from chapter 4 ([link](https://runestone.academy/runestone/books/published/pythonds3/BasicDS/ImplementinganOrderedList.html)).As per the previous exercise, we will implement the remaining methods. Acknowledging that this is an ordered list, we are left to implement only the `remove()` and `pop()` methods.<jupyter_code>class Node:
    """A node of a linked list"""

    def __init__(self, node_data):
        self._data = node_data
        self._next = None

    def get_data(self):
        """Get node data"""
        return self._data

    def set_data(self, node_data):
        """Set node data"""
        self._data = node_data

    data = property(get_data, set_data)

    def get_next(self):
        """Get next node"""
        return self._next

    def set_next(self, node_next):
        """Set next node"""
        self._next = node_next

    next = property(get_next, set_next)

    def __str__(self):
        """String"""
        return str(self._data)


class OrderedList:
    """Ordered linked list implementation"""
    def __init__(self):
        self.head = None

    def search(self, item):
        """Search for a node with a specific value"""
        current = self.head
        while current is not None:
            if current.data == item:
                return True
            if current.data > item:
                return False
            current = current.next

        return False

    def add(self, item):
        """Add a new node"""
        current = self.head
        previous = None
        temp = Node(item)

        while current is not None and current.data < item:
            previous = current
            current = current.next

        if previous is None:
            temp.next = self.head
            self.head = temp
        else:
            temp.next = current
            previous.next = temp

    def is_empty(self):
        """Is the list empty"""
        return self.head == None

    def size(self):
        """Size of the list"""
        current = self.head
        count = 0
        while current is not None:
            count = count + 1
            current = current.next

        return count

    def remove(self, item):
        current = self.head
        prev = None 

        while current is not None and current.item < item:
            prev = current 
            current = current.next

        if current is None or current.item > item:
            raise Exception(f"Item {item} not found!")
        elif prev is None:
            self.head = current.next
        else:
            prev.next = current.next
    
    def pop(self, pos=None):
        current = self.head
        prev = None 
        i = 0

        pos = pos if pos is not None else self.size()

        if pos > self.size():
            raise Exception(f"List size is {self.size()}!")

        while i < pos and current is not None:
            prev = current 
            current = current.next
            i += 1

        item = current.item
        prev.next = current.next

        return item<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09172546504169339, 'fraction_numerical': 0.001924310455420141, 'mean_word_length': 1.7650709219858156, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '166210', 'license': 'MIT', 'n_tokens_mistral': 861, 'n_tokens_neox': 822, 'n_words': 287, 'path': 'chapter4/ordered_list.ipynb', 'repo_name': 'RiccardoMPesce/PythonDS3-Selected-Assignments', 'size': '3118'}