1. Introduction

The map() function is a powerful functional programming construct that we can use to transform elements of an array in Kotlin. The map() function creates a new array with the transformed values, but what if we want to modify the original array directly? In this article, we’ll explore how to use the map() function in Kotlin and compare it to modifying mutable collection values in place by creating an extension function**.

2. How the map() Function Works with a Kotlin Array

The map() function in Kotlin operates on an Array and applies a transformation function to each element of the Array. The result of the map() operation is a new Array that contains the transformed values:

@Test
fun `Should map an array by doubling all numbers`() {
    val numbers = arrayOf(1, 2, 3, 4, 5)
    val doubledNumbers = numbers.map { it * 2 }

    assertContentEquals(listOf(2, 4, 6, 8, 10), doubledNumbers)
}

In this example, the map() function is used to double each element of the numbers array. The resulting array, doubledNumbers, contains the transformed values.

It’s important to note that the map() function does not modify the original array. Instead, it creates a new array with the transformed values. This means that if we want to modify the original array, we need to change the values stored in it directly. If we just want to change our reference to point to the new Array, the code required for that is as simple as:

@Test
fun `Should reassign the original variable to the new array`() {
    var numbers = arrayOf(1, 2, 3, 4, 5)
    numbers = numbers.map { it * 2 }.toTypedArray()

    assertContentEquals(arrayOf(2, 4, 6, 8, 10), numbers)
}

3. Mutating the Original Array

If we want to modify the original array without creating a new array, we can create an extension function that applies the transformation function to each element of the Array and mutates it in place:

fun <T> Array<T>.mapInPlace(transform: (T) -> T): Array<T> {
    for (i in this.indices) {
        this[i] = transform(this[i])
    }
    return this
}

@Test
fun `Should replace array values in the original array`() {
    val numbers = arrayOf(1, 2, 3, 4, 5)
    numbers.mapInPlace { it * 2 }

    assertContentEquals(arrayOf(2, 4, 6, 8, 10), numbers)
}

In this example, we define an extension function called mapInPlace() that takes a transformation function as an argument. The function loops through each element of the Array and applies the transformation function to it, mutating the Array in place.

4. Pros and Cons

The map() function is a powerful tool in the functional programming paradigm that allows us to transform an Array into a new Collection with modified values. On the other hand, the mapInPlace() function is not a functional programming concept, as it breaks immutability. Let’s explore some pros and cons of using each function.

4.1. Why Use map()

There are several advantages to using the map() function for array transformations. Let’s explore some of the key benefits it offers.

Pros:

  • Immutability: One of the biggest advantages of using the map() function is that it does not modify the original array. Instead, it creates a new array with the transformed values, which helps us maintain immutability and avoid introducing unexpected bugs.
  • Ease of use: It’s a one-liner that clearly expresses our intention to transform the array into a new collection.
  • Functional programming: As we mentioned before, map() is a functional programming concept. By using it, we can write more concise and expressive code that is easier to reason about and maintain.

Cons:

  • Memory usage: map() returns a new Collection, which can be memory-intensive when working with large data sets.
  • Creation of intermediary collections: With map(), each transformation step creates an intermediary collection that needs to be created, stored, and eventually garbage collected. This can lead to increased memory usage and potential performance impacts, especially if the original array is not needed after the transformation.

4.2. Why Use mapInPlace()

Here, we’ll discuss the benefits and drawbacks of using mapInPlace(), such as performance gains and reduced memory usage.

Pros:

  • Performance: The main advantage of using mapInPlace() is performance. Because we’re modifying the original array in place, we avoid the overhead of creating a new array and copying the transformed values.
  • Flexibility in specific scenarios: While mutability can introduce complexities, mapInPlace() can offer simplicity and convenience in certain situations. When dealing with a large array that needs to be modified in place, using mapInPlace() may provide a straightforward and efficient solution.

Cons:

  • Mutability: The main disadvantage of using mapInPlace() is that it introduces mutability. We’re modifying the original array, which can lead to unexpected bugs and make our code harder to reason about.
  • Not functional programming: As we mentioned before, mapInPlace() is not a functional programming concept. By using it, we’re breaking the immutability practice and introducing mutability to our code.

5. Conclusion

The map() function is a powerful tool for transforming elements in an Array in Kotlin. It creates a new Array with the transformed values, which is a safe and functional approach. However, in some cases, we may want to modify the original Array directly, which can be accomplished using an extension function that maps the elements in place.

While mapping in place can be useful in certain scenarios, it’s important to be aware of the trade-offs. Mutating state directly can make code harder to understand, leading to bugs and errors. In general, it’s a good practice to use immutable collections whenever possible, as they promote safer and more functional programming practices.

That being said, there may be cases where modifying the original array in place is the best approach for a specific use case. As always, the code used in this article is available over on GitHub.