Search code examples
pythonpython-3.xlinked-listdoubly-linked-list

Filtering nodes in a DLL


Here is what I have so far, I want to create the function that would remove elements lower than a specified value in the doubly linked list or above the specified value.

class DoublyLinkedList:

    class Node:
        """ Nodes in list """

        def __init__(self, element, prev=None, next_node=None):
            self.element = element
            self.prev = prev
            self.next = next_node

    def __init__(self):
        self._header = self.Node(None, None, None)
        self._trailer = self.Node(None, None, None)
        self._header.next = self._trailer
        self._trailer.prev = self._header
        self._size = 0

    def append(self, element):

        :arg element: the value to add to this list
        
        new_node = self.Node(element, self._trailer.prev, self._trailer)
        self._trailer.prev.next = new_node
        self._trailer.prev = new_node
        self._size += 1

    def __len__(self):
        return self._size

    def __str__(self):

        # Python's list is used here to avoid string concatenation
        result = []

        current = self._header.next
        for i in range(len(self)):
            result.append(current.element)
            current = current.next

        return str(result)

    def remove(self, low, high):
        for element in self:
            try:
    
            if element.next < low:
                element.next = element.next.next
        
            elif element.next > high:
                element.next = element.next.next
        
            except Exception as e:
                print('low must be less than or equal to high')
        
        pass  

^^ That is what I've tried so far ^^ here is how I wanted it to work: I'm not sure how to get it to filter out the higher or lower values

DoublyLinkedList.append(5)
DoublyLinkedList.append(7)
DoublyLinkedList.append(8)
DoublyLinkedList.append(3)
DoublyLinkedList.append(9)

[5, 7, 8, 3, 9]


DoublyLinkedList.remove(5,8)

its output should be:

[5, 7, 8]

Solution

  • Some issues in your code:

    • append has a line that should be a comment (starting with #)
    • for element in self: will not work, as self is not iterable. Also, it is rarely a good idea to iterate over a collection with a for loop when you are planning to remove items from that same collection. It will be better to use a form of iteration that you have already used in the __str__ method.
    • element.next < low is comparing two different types: .next is a node, while low is a number. Calling that loop variable element is confusing, as that is also the name of the attribute of your nodes. You want to have something like current.next.element < low.
    • If the above is corrected, there is no reason why the try block should trigger an exception, let be that it has to do with how low and high relate to eachother. If you want to output a message when high > low, then don't do that in the loop, but just test for that condition before starting the loop.
    • When you remove one node, you should also decrease the list size.
    • You can avoid code repetition by using one if to compare with low and high in one expression, using operator chaining
    • DoublyLinkedList is the class, but a list should be an instance of that class. So you need to first create that instance, and then call the methods on that instance, not on the class.

    Here is a correction of your code:

    class DoublyLinkedList:
    
        class Node:
            """ Nodes in list """
    
            def __init__(self, element, prev=None, next_node=None):
                self.element = element
                self.prev = prev
                self.next = next_node
    
        def __init__(self):
            self._header = self.Node(None, None, None)
            self._trailer = self.Node(None, None, None)
            self._header.next = self._trailer
            self._trailer.prev = self._header
            self._size = 0
    
        def append(self, element):
            # :arg element: the value to add to this list
            new_node = self.Node(element, self._trailer.prev, self._trailer)
            self._trailer.prev.next = new_node
            self._trailer.prev = new_node
            self._size += 1
    
        def __len__(self):
            return self._size
    
        def __str__(self):
            result = []
            current = self._header.next
            for i in range(len(self)):
                result.append(current.element)
                current = current.next
            return str(result)
    
        def remove(self, low, high):
            # Perform the check before the loop
            if low > high:
                print('low must be less than or equal to high')
                return
            # Iterate the nodes like in __str__, but start one node earlier
            current = self._header
            for i in range(len(self)):
                # Don't compare the node, but its element.
                # Use chained comparison;
                if low <= current.next.element <= high:
                    # Only move to next node when not removing
                    current = current.next
                else:
                    current.next = current.next.next
                    self._size -= 1  # Also reduce size
    
    # Should create an instance and work with that
    lst = DoublyLinkedList()
    lst.append(5)
    lst.append(7)
    lst.append(8)
    lst.append(3)
    lst.append(9)
    print(lst)  # [5, 7, 8, 3, 9]
    lst.remove(5,8)
    print(lst)  # [5, 7, 8]