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.
Exploring the use of range expressions to iterate through alphabet characters
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...
- 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.
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.