Kotlin Sequence

Introduction

In Kotlin, the Sequence interface represents a lazily evaluated collection of elements. Unlike Iterable collections, sequences perform operations such as map and filter lazily, meaning they only evaluate elements as needed. This can lead to performance improvements, especially when working with large datasets.

Table of Contents

  1. What is Sequence?
  2. Creating a Sequence
  3. Common Functions
  4. Examples of Sequence
  5. Real-World Use Case
  6. Conclusion

1. What is Sequence?

The Sequence interface in Kotlin represents a lazily evaluated collection of elements. Operations on sequences are intermediate or terminal. Intermediate operations return a new sequence, while terminal operations return a result or produce a side-effect.

Syntax

interface Sequence<out T>

2. Creating a Sequence

You can create a sequence using the sequenceOf function, converting a collection to a sequence using the asSequence function, or using the generateSequence function.

Example

val seq = sequenceOf(1, 2, 3, 4, 5)
val listSeq = listOf(1, 2, 3, 4, 5).asSequence()
val generatedSeq = generateSequence(1) { it + 1 } // Infinite sequence starting from 1

3. Common Functions

Filtering Functions

  • filter(predicate: (T) -> Boolean): Returns a sequence containing only elements matching the given predicate.
  • filterNot(predicate: (T) -> Boolean): Returns a sequence containing only elements not matching the given predicate.
  • filterNotNull(): Returns a sequence containing only non-null elements.

Transformation Functions

  • map(transform: (T) -> R): Returns a sequence containing the results of applying the given transform function to each element in the original sequence.
  • flatMap(transform: (T) -> Sequence<R>): Returns a sequence of all elements from results of the transform function being invoked on each element of the original sequence.

Other Common Functions

  • take(n: Int): Returns a sequence containing the first n elements.
  • takeWhile(predicate: (T) -> Boolean): Returns a sequence containing the first elements that satisfy the predicate.
  • drop(n: Int): Returns a sequence containing all elements except the first n elements.
  • dropWhile(predicate: (T) -> Boolean): Returns a sequence containing all elements except the first elements that satisfy the predicate.
  • distinct(): Returns a sequence containing only distinct elements.
  • sorted(): Returns a sequence containing all elements in natural order.
  • sortedBy(selector: (T) -> R): Returns a sequence containing all elements sorted according to the selector function.
  • toList(): Returns a list containing all elements of the sequence.
  • toSet(): Returns a set containing all elements of the sequence.

4. Examples of Sequence

Example 1: Basic Usage of Sequence

This example demonstrates how to create and use a basic sequence.

fun main() {
    val seq = sequenceOf(1, 2, 3, 4, 5)
    seq.forEach { println(it) }
}

Output:

1
2
3
4
5

Explanation:
This example creates a sequence of integers and prints each element.

Example 2: Filtering a Sequence

This example demonstrates how to filter elements in a sequence.

fun main() {
    val seq = sequenceOf(1, 2, 3, 4, 5)
    val filteredSeq = seq.filter { it % 2 == 0 }
    filteredSeq.forEach { println(it) }
}

Output:

2
4

Explanation:
This example filters out the odd numbers and prints the even numbers in the sequence.

Example 3: Transforming a Sequence

This example demonstrates how to transform elements in a sequence using the map function.

fun main() {
    val seq = sequenceOf(1, 2, 3, 4, 5)
    val mappedSeq = seq.map { it * 2 }
    mappedSeq.forEach { println(it) }
}

Output:

2
4
6
8
10

Explanation:
This example multiplies each element in the sequence by 2 and prints the results.

Example 4: Using flatMap with a Sequence

This example demonstrates how to use the flatMap function to transform elements in a sequence into another sequence.

fun main() {
    val seq = sequenceOf(1, 2, 3)
    val flatMappedSeq = seq.flatMap { sequenceOf(it, -it) }
    flatMappedSeq.forEach { println(it) }
}

Output:

1
-1
2
-2
3
-3

Explanation:
This example transforms each element into a sequence of the element and its negation, then flattens the results into a single sequence.

Example 5: Taking Elements from a Sequence

This example demonstrates how to take the first n elements from a sequence.

fun main() {
    val seq = generateSequence(1) { it + 1 } // Infinite sequence starting from 1
    val takenSeq = seq.take(5)
    takenSeq.forEach { println(it) }
}

Output:

1
2
3
4
5

Explanation:
This example takes the first 5 elements from an infinite sequence and prints them.

Example 6: Dropping Elements from a Sequence

This example demonstrates how to drop the first n elements from a sequence.

fun main() {
    val seq = sequenceOf(1, 2, 3, 4, 5)
    val droppedSeq = seq.drop(2)
    droppedSeq.forEach { println(it) }
}

Output:

3
4
5

Explanation:
This example drops the first 2 elements from the sequence and prints the remaining elements.

Example 7: Distinct Elements in a Sequence

This example demonstrates how to get distinct elements from a sequence.

fun main() {
    val seq = sequenceOf(1, 2, 2, 3, 3, 3, 4)
    val distinctSeq = seq.distinct()
    distinctSeq.forEach { println(it) }
}

Output:

1
2
3
4

Explanation:
This example removes duplicate elements and prints the distinct elements in the sequence.

Example 8: Sorting a Sequence

This example demonstrates how to sort elements in a sequence.

fun main() {
    val seq = sequenceOf(5, 3, 1, 4, 2)
    val sortedSeq = seq.sorted()
    sortedSeq.forEach { println(it) }
}

Output:

1
2
3
4
5

Explanation:
This example sorts the elements in the sequence and prints them in ascending order.

Example 9: Converting a Sequence to a List

This example demonstrates how to convert a sequence to a list.

fun main() {
    val seq = sequenceOf(1, 2, 3, 4, 5)
    val list = seq.toList()
    println(list) // Output: [1, 2, 3, 4, 5]
}

Output:

[1, 2, 3, 4, 5]

Explanation:
This example converts a sequence to a list and prints the list.

Example 10: Converting a Sequence to a Set

This example demonstrates how to convert a sequence to a set.

fun main() {
    val seq = sequenceOf(1, 2, 2, 3, 3, 3, 4)
    val set = seq.toSet()
    println(set) // Output: [1, 2, 3, 4]
}

Output:

[1, 2, 3, 4]

Explanation:
This example converts a sequence to a set and prints the set, showing only distinct elements.

5. Real-World Use Case: Processing a Large Dataset

You can use sequences to process a large dataset efficiently by taking advantage of lazy evaluation.

Example: Processing a Large Dataset

fun main() {
    val largeDataset = generateSequence(1) { it + 1 }.take(1_000_000)
    val processedData = largeDataset
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .take(10)
        .toList()

    println(processedData) // Output: [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
}

Output:

[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

Comments