0

I wanted to extend karin's answer here where she uses a for loop for loop to print the linked list.

I would like to have __str__ method that is part of SinglyLinkedList but would like to reuse the __iter__ method as it is without the except clause which comes with StopIteration given that the answers here say that try statements are cheap except when catching the exception. Is there anyway to go about it? Is it even possible? If I understand this correctly, the for loop calls __iter__ so it would run into the same StopIteration.

The code that I have that works is here.

from typing import Optional
# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

    def __str__(self):
        return f"Node:{self.val} Next:{self.next.val if self.next else 'None'}\n"

class SinglyLinkedList():
    def __init__(self):
        self.head = None
        self.tail = None

    def __iter__(self):
        node = self.head
        
        while node:
            yield node 
            node = node.next

    def add(self, node):
        if not self.head:
            self.head = node 
        else:
            self.tail.next = node
        
        self.tail = node

    def __str__(self):
        iterator = self.__iter__()
        values = []
        try: 
            while True:
                values.append( str(next(iterator).val) )
        except StopIteration:
            pass

        return "->".join(values)
one = ListNode(1)
two = ListNode(2)
three = ListNode(3)
four = ListNode(4)
five = ListNode(5)

ll = SinglyLinkedList()
ll.add(one)
ll.add(two)
ll.add(three)
ll.add(four)
ll.add(five)
print(ll)

which gives me the output that I would like.

1->2->3->4->5

The other way I could do think of is to reuse code a while loop

def __str__(self):
        values = []
        node = self.head

        while node:
            values.append( str(node.val) )
            node = node.next
        return "->".join(values)
heretoinfinity
  • 1,528
  • 3
  • 14
  • 33

1 Answers1

1

You could use a simple comprehension here:

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

Good news:

  • no list to build element by element (no list at all in fact, but a mere generator)
  • no explicit handling of StopIteration (handled under the hood by the comprehension)

I would not expect a major performance increase though, but at least it is shorter to write and maintain...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252