4

It turned out to be an error as a time limit was exceeded, but I've already raised the StopIteration...

I think I did something wrong for my iteration part, but it's really hard to find the error. The test output keeps running and even printed out the None value. How does it happen?

class LinkedListIterator:
    def __init__(self, head):
        self.__current = head.get_next()

    def __iter__(self):
        return self

    def __next__(self):
        if self.__current == None:
            raise StopIteration
        else:
            item = self.__current.get_data()
            self.__current = self.__current.get_next()
            return item

These were the inputs I used to run the program:

my_list = LinkedListDLL()
my_list.add_to_head(1)
print("Contents:", end=" ")
for node in my_list:
    print(node, end=" ")
print()
7
  • How is your node class defined? Commented Sep 26, 2018 at 4:44
  • Please update your question with the class definition of your NodeDLL class so it can be properly indented. Commented Sep 26, 2018 at 4:50
  • yes i've been uploaded more detailed for my code Commented Sep 26, 2018 at 4:59
  • Can you copy and paste your code as text like you did for LinkedListIterator, instead of posting it as a picture, so we can easily run it and try it out ourselves? Commented Sep 26, 2018 at 5:07
  • oops sorry for that... it's my first time to use this website Commented Sep 26, 2018 at 5:27

2 Answers 2

1

This code is meant to stop iteration when it reaches the head of the list.

    if self.__current == None:
        raise StopIteration

However, you represent the head with a NodeDLL object which is different from None.

You could keep a reference to the head and check against that instead:

class LinkedListIterator:
    def __init__(self, head):
        self._head = head
        self._current = head.get_next()

    def __iter__(self):
        return self

    def __next__(self):
        if self._current is self._head:
            raise StopIteration
        else:
            item = self._current.get_data()
            self._current = self._current.get_next()
            return item
Sign up to request clarification or add additional context in comments.

Comments

1

What you want to implement is the API of a MutableSequence with the implementation of a doubly-linked-list.

To do that in Python, you should rely on collections.abc which can guide you through the process of implementing all required methods.

By example, a linked-list is actually a class inheriting from MutableSequence.

from collections.abc import MutableSequence

class LinkedList(MutableSequence):
    pass

ll = LinkedList()

On instantiation of a class which has some abstract methods not yet written, you will get a TypeError which will guide you through which methods need to be implemented.

TypeError: Can't instantiate abstract class LinkedList with abstract methods __delitem__, __getitem__, __len__, __setitem__, insert

In particular, note that a list or a linked-list is not an iterator, it is an iterable. What this means is the __iter__ method should not return self and rely on __next__, it should instead return a brand new iterator on the content of the linked-list.

In other words, you can iterate only once through an iterator and multiple times through and iterable.

Full implementation

It turns out I have a full implementation of a doubly-linked-list implemented that way. You can have a look.

from collections.abc import MutableSequence

class LinkedList(MutableSequence):
    class _Node:
        def __init__(self, value, _next=None, _last=None):
            self.value, self._next, self._last = value, _next, _last

        def __str__(self):
            return f'Node({self.value})'

    def __init__(self, iterable=()):
        self.start = None
        self.last = None

        empty = object()
        iterable = iter(iterable)
        first = next(iterable, empty)

        if first is empty:
            return

        current = self._Node(first)
        self.start, self.last = current, current

        for value in iterable:
            new_node = self._Node(value, _last=self.last)
            self.last._next = new_node
            self.last = new_node


    def __len__(self):
        if self.start is None:
            return 0
        else:
            return sum(1 for _ in self)

    def __iter_nodes(self):
        current = self.start

        while current is not None:
            yield current
            current = current._next

    def __reversed_iter_nodes(self):
        current = self.last

        while current is not None:
            yield current
            current = current._last

    def __iter__(self):
        for node in self.__iter_nodes():
            yield node.value

    def __reversed__(self):
        for node in self.__reversed_iter_nodes():
            yield node.value

    def __get_node(self, index):
        if index >= 0:
            for item in self.__iter_nodes():
                if index == 0:
                    return item
                index -= 1
        else:
            for item in self.__reversed_iter_nodes():
                if index == 0:
                    return item
                index += 1
        raise IndexError

    def __getitem__(self, index):
        if index >= 0:
            for item in self:
                if index == 0:
                    return item.value
                index -= 1
        else:
            for item in reversed(self):
                if index == 0:
                    return item.value
                index += 1
        raise IndexError

    def __setitem__(self, key, value):
        self[key].value = value

    def __delitem__(self, key):
        node = self[key]
        if node._last:
            node._last._next = node._next
        if node._next:
            node._next._last = node._last

    def insert(self, index, value):
        if index > len(self):
            self.last = self._Node(value, _last=self.last)
        else:
            where = self.__get_node(index)
            _last = where._last
            new_node = self._Node(value, _next=where, _last=_last)
            if _last:
                _last._next = new_node
            else:
                self.start = new_node

            where._last = new_node

Example

ll = LinkedList(range(1, 5))
print(*ll)

print(*reversed(ll))

ll.insert(2, 'foo')
print(*ll)

Output

1 2 3 4
4 3 2 1
1 2 foo 3 4

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.