yoman
yoman

Reputation: 105

linked list iterator python

I want to write a function called print_iterator_explicit() which prints all of the items in a linked list by making use of the Iterator. However, you are not permitted to use the standard "for ... in" loop syntax - instead you must create the Iterator object explicitly, and print each item by calling the next() method

Use the iter() and next() methods in your function definition - and remember to handle the StopIteration exception!

Below is what I've tried, but the print_iterator_explicit seems to have some problem which I can only print the first element but not the whole list.

class LinkedListIterator:

def __init__(self, head):
    self.current = head

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

class LinkedList:

def __init__(self):
    self.head = None

def __iter__(self):
    return LinkedListIterator(self.head)

def add(self, item): 
    new_node = Node(item)
    new_node.set_next(self.head)
    self.head = new_node

def print_iterator_explicit(items):
    it = items.__iter__()
    print(it.__next__())

Upvotes: 8

Views: 15434

Answers (4)

Henrik Melfald Kittang
Henrik Melfald Kittang

Reputation: 188

You can use the yield keyword to make a generator so you dont have to implement __next__()

class LinkedList:
    def __init__(self):
        self.head = None

    def __iter__(self):
        curNode = self.head
        while curNode:
            yield curNode.value
            curNode = curNode.nextNode

    def add(self, item): 
        new_node = Node(item)
        new_node.set_next(self.head)
        self.head = new_node

And in your print_iterator_explicit function you can do it like this

def print_iterator_explicit(items):       
    iterator = iter(ll)
    while True:
        try:
            print(next(iterator))
        except StopIteration:
            break

Check out this link for more information on iterators and generators: Iterators and generators

A little side note: your head variable is behaving like a tail. In a linked list the first node is called the head and the last is called the tail

Upvotes: 6

Craggl
Craggl

Reputation: 31

Instead of a helper class, I found that a helper function is a bit cleaner:

class ListNode():
  def __init__(self, val):
    self.val = val
    self.next = None

  def __str__(self):
    return ' -> '.join(str(v) for v in self)

  def __iter__(self):
    return ListIterator(self)

def ListIterator(head):
  while head:
    yield head.val
    head = head.next

Upvotes: 1

ssword
ssword

Reputation: 915

Just as mentioned by @abarnert , you always need a __iter__ method for the iterator class.

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

    def __iter__(self):
        return self

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

class LinkedList:
    def __init__(self):
        self.head = None

    def __iter__(self):
        return LinkedListIterator(self.head)

    def add(self, item): 
        new_node = Node(item)
        new_node.set_next(self.head)
        self.head = new_node

Now that your class is iterable, you can use "for...in" loop:

test_list = LinkedList()
test_list.add(1)
test_list.add(2)
test_list.add(3)
for item in test_list:
    print(item)

Please check the tutorial here.

Upvotes: 7

abarnert
abarnert

Reputation: 366213

To iterate all of the items, you need some kind of loop—whether explicit or implicit.


You’re not allowed to use for val in items:, which is the most obvious solution, but you can do a loop with while:

it = iter(items)
while True:
    try:
        print(next(it))
    except StopIteration:
        break

This is, in fact, very close to what a for loop does under the covers.


Or you can loop implicitly, say, with the list constructor—or, even better, just by splatting the iterator:

print(*items, sep='\n')

(Of course if this is a homework assignment, that's the kind of answer that will get you an F if the teacher thinks you don't understand why it works, but maybe an A if you can explain it…)


Or you can use recursion:

def printemall(items):
    print(next(items))
    printemall(items)
try:
    printemall(iter(items))
except StopIteration:
    pass

Upvotes: 2

Related Questions