Book Image

Kotlin Standard Library Cookbook

By : Samuel Urbanowicz
Book Image

Kotlin Standard Library Cookbook

By: Samuel Urbanowicz

Overview of this book

For developers who prefer a more simplistic approach to coding, Kotlin has emerged as a valuable solution for effective software development. The Kotlin standard library provides vital tools that make day-to-day Kotlin programming easier. This library features core attributes of the language, such as algorithmic problems, design patterns, data processing, and working with files and data streams. With a recipe-based approach, this book features coding solutions that you can readily execute. Through the book, you’ll encounter a variety of interesting topics related to data processing, I/O operations, and collections transformation. You’ll get started by exploring the most effective design patterns in Kotlin and understand how coroutines add new features to JavaScript. As you progress, you'll learn how to implement clean, reusable functions and scalable interfaces containing default implementations. Toward the concluding chapters, you’ll discover recipes on functional programming concepts, such as lambdas, monads, functors, and Kotlin scoping functions, which will help you tackle a range of real-life coding problems. By the end of this book, you'll be equipped with the expertise you need to address a range of challenges that Kotlin developers face by implementing easy-to-follow solutions.
Table of Contents (11 chapters)

Exploring the use of range expressions to iterate through alphabet characters

Ranges, provided by the Kotlin standard library, are a powerful solution for implementing iteration and conditional statements in a natural and safe way. A range can be understood as an abstract data type that represents a set of iterable elements and allows iteration through them in a declarative way. The ClosedRange interface from the kotlin.ranges package is a basic model of the range data structure. It contains references to the first and last elements of the range and provides the contains(value: T): Boolean and isEmpty(): Boolean functions, which are responsible for checking whether the specified element belongs to the range and whether the range is empty. In this recipe, we are going to learn how to declare a range that consists of alphabet characters and iterate through it in a decreasing order.

Getting ready

The Kotlin standard library provides functions that allow the declaration of ranges for the integral, primitive types, such as Int, Long, and Char. To define a new range instance, we can use the rangeTo() function. For example, we can declare a range of integers from 0 to 1000 in the following way:

val range: IntRange = 0.rangeTo(1000)

The rangeTo() function has also its own special operator equivalent, .., which allows the declaration of a range with a more natural syntax:

val range: IntRange = 0..1000

Also, in order to declare a range of elements in a decreasing order, we can use the downTo() function.

How to do it...

  1. Declare a decreasing range of alphabet characters:
'Z' downTo 'A'

2. Create a for loop to traverse the range:

for (letter in 'Z' downTo 'A') print(letter)

How it works...

As a result, we are going to get the following code printed out to the console:

ZYXWVUTSRQPONMLKJIHGFEDCBA

As you can see, there is also a downTo() extension function variant for the Char type. We are using it to create a range of characters from Z to A. Note that, thanks for the infix notation, we can omit the brackets while invoking the function—'Z' downTo 'A'.

Next, we are creating a for loop, which iterates through the range and prints out the subsequent Char elements. Using the in operator, we are specifying the object that is being iterated in the loop—and that's it! As you can see, the Kotlin syntax for the for loop is neat and natural to use.

Implementations of ranges of the primitive types, such as IntRange, LongRange, and CharRange, also contain Iterator interface implementations under the hood. They are being used while traversing the range using the for loop under the hood. In fact, the range implementing the Iterable interface is called a progression. Under the hood, the IntRange, LongRange, and CharRange classes inherit from the IntProgression, LongProgression, and CharProgression base classes, and they provide the implementations of the Iterator interface internally.

There's more...

There is also a convenient way to reverse the order of an already-defined progression. We can do so with the extension function provided for the IntProgression, LongProgression, and CharProgression types, which is called reversed(). It returns new instances of progressions with a reversed order of elements. Here is an example of how to use the reversed() function:

val daysOfYear: IntRange = 1..365
for(day in daysOfYear.reversed()) {
println("Remaining days: $day")
}

The preceding for loop prints the following text to the console:

Remaining days: 365
Remaining days: 364
Remaining days: 363

Remaining days: 2
Remaining days: 1

The Kotlin standard library offers also another handy extension function called until(), which allows the declaration of ranges that don't include the last element. It is pretty useful when working with classes that contain internal collections and don't provide elegant interfaces to access them. A good example would be the Android ViewGroup class, which is a container for the child View type objects. The following example presents how to iterate through the next indexes of any given ViewGroup instance children in order to modify the state of each of the children:

val container: ViewGroup = activity.findViewById(R.id.container) as ViewGroup
(0 until container.childCount).forEach {
val child: View = container.getChildAt(it)
child.visibility = View.INVISIBLE
}

The until() infix function helps to make the loop conditions clean and natural to understand.

See also

  • This recipe gave us an insight into how Kotlin standard library implementations of ranges for primitives are easy to work with. A problem can appear if we want to traverse non-primitive types using the for loop. However, it turns out we can easily declare a range for any Comparable type. This will be shown in the Building custom progressions to traverse dates recipe.
  • As you have noticed, we are using the in operator to specify the object that is being iterated in the loop. However, there are also other scenarios where the in and !in operators can be used together with ranges. We will investigate them in depth in the Using range expressions with flow control statements recipe.