Range Over Iterators in Kotlin
On this page
Starting with version 1.23, Go has added support for iterators, which lets us range over pretty much anything!
Let’s look at the List
type from the previous example again. In that example, we had an AllElements
method that returned a slice of all elements in the list. With Kotlin iterators (known as sequences), we can do it better - as shown below.
Code Example
class List<T> {
private var head: Element<T>? = null
private var tail: Element<T>? = null
private class Element<T>(val value: T, var next: Element<T>? = null)
fun push(value: T) {
if (tail == null) {
head = Element(value)
tail = head
} else {
tail!!.next = Element(value)
tail = tail!!.next
}
}
fun all(): Sequence<T> = sequence {
var current = head
while (current != null) {
yield(current.value)
current = current.next
}
}
}
fun genFib(): Sequence<Int> = sequence {
var a = 1
var b = 1
while (true) {
yield(a)
val next = a + b
a = b
b = next
}
}
fun main() {
val lst = List<Int>()
lst.push(10)
lst.push(13)
lst.push(23)
for (e in lst.all()) {
println(e)
}
val all = lst.all().toList()
println("all: $all")
for (n in genFib()) {
if (n >= 10) break
println(n)
}
}
Explanation
Define the List Class
We start by defining a generic List
class to store elements.
class List<T> {
private var head: Element<T>? = null
private var tail: Element<T>? = null
private class Element<T>(val value: T, var next: Element<T>? = null)
// Other methods...
}
Push Method
The push
method adds an element to the end of the list.
fun push(value: T) {
if (tail == null) {
head = Element(value)
tail = head
} else {
tail!!.next = Element(value)
tail = tail!!.next
}
}
All Method
The all
method returns a Kotlin sequence, which is an iterator that lazily evaluates the elements in the list.
fun all(): Sequence<T> = sequence {
var current = head
while (current != null) {
yield(current.value)
current = current.next
}
}
Generate Fibonacci Sequence
We define a genFib
function that generates an infinite sequence of Fibonacci numbers using a Kotlin sequence.
fun genFib(): Sequence<Int> = sequence {
var a = 1
var b = 1
while (true) {
yield(a)
val next = a + b
a = b
b = next
}
}
Main Function
In the main
function, we create a List
, add elements to it, and then iterate over them using the all
method.
fun main() {
val lst = List<Int>()
lst.push(10)
lst.push(13)
lst.push(23)
for (e in lst.all()) {
println(e)
}
val all = lst.all().toList()
println("all: $all")
for (n in genFib()) {
if (n >= 10) break
println(n)
}
}
This code demonstrates how to iterate over custom data structures using Kotlin sequences, providing a modern and idiomatic way to handle iteration in Kotlin.