Search code examples
kotlindata-structureslinked-listsingly-linked-list

How to implement iterator for a LinkedList using Kotlin


I am implementing LinkedList in Kotlin. I wanted to implement Iterator interface so that I can for each on the LinkedList like so linkedlist.forEach{}.

here is the code that I have

class SinglyLinkedList<T> : Iterator<T> {

    var head: SinglyLinkedListNode<T>? = null
        private set(value) {
            cursor = value
            field = value
        }

    var count = 0
        private set

    // This is needed for iterator functionality.
    private var cursor: SinglyLinkedListNode<T>? = null

 override fun hasNext(): Boolean {
        // the problem is when I return in the middle of the loop
        // then start new for each
        // cursor is not equal head
        return if (cursor == null){
           // if this is the last time, reset cursor so that next time we start from the begining
            cursor = head
            false
        } else {
            true
        }
    }
    override fun next(): T {
        val temp = cursor
        cursor = cursor!!.next
        return temp!!.value
    }
}

the issue happens when I do something like this

linkedlist.forEach{
 if(it) == 1 return
}

then I try to forEach again, it will continue from the last element it stopped at.


Solution

  • then I try to forEach again, it will continue from the last element it stopped at.

    Yes, that is what an Iterator is supposed to do. An Iterator is a stateful thing - it knows which element it is currently "at". Do you want your linked list to know which element it is currently "at"? You probably don't, do you? You want your linked list, and the iterator of that linked list, to be different things.

    The list can be iterable, meaning that you can get an iterator from the list.

    class SinglyLinkedList<T> : Iterable<T> {
    
        var head: SinglyLinkedListNode<T>? = null
            private set
    
        var count = 0
            private set
    
        override fun iterator() = object: Iterator<T> {
            private var cursor: SinglyLinkedListNode<T>? = head
    
            override fun hasNext() = cursor != null
    
            override fun next() = (cursor?.value ?: throw NoSuchElementException()).also {
                cursor = cursor?.next
            }
        }
    }
    

    Now doing forEach on the list will create an iterator of the list, and after iterating through the list (no matter which element you have iterated to), the iterator will be discarded. The next time you call forEach, a brand new iterator gets created.