1. Introduction

When dealing with arrays in Kotlin, it’s often necessary to extract a portion of the array that falls between two specific positions. This operation is known as getting a subarray of an Array between given positions.

In this tutorial, we’ll explore various methods of achieving this task in Kotlin.

2. Programmatic Approach

To begin with, we can solve this problem by copying the elements from the start and end index from the first Array to a new one:

fun customMethod(array: Array<Int>, start: Int, end: Int): IntArray {
    val subArray = IntArray(end - start + 1)
    for (i in subArray.indices) {
        subArray[i] = array[start + i]
    }

    return subArray
}

Now, let’s test our method for correctness:

@Test
fun `using custom approach`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = customMethod(array, 2, 4)
    assertArrayEquals(intArrayOf(3, 4, 5), subArray)
}

3. Using the System.arraycopy() Method

The System.arraycopy() method is another easy way to achieve our desired results. It copies the elements from the range we specify in the source Array to the destination Array:

@Test
fun `using arraycopy() method`() {
    val arr = arrayOf(1, 2, 3, 4, 5, 6)
    val start = 2
    val end = 4

    val subArray = arrayOfNulls<Int>(end - start + 1)
    System.arraycopy(arr, start, subArray, 0, subArray.size)
    assertArrayEquals(arrayOf(3, 4, 5), subArray)
}

4. Using the slice() Method

We can also get a subarray of an array between given positions by using the slice() method. This method takes a range of positions and returns a subarray that falls between those positions:

@Test
fun `using slice() method`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = array.slice(2..4)
    assertArrayEquals(intArrayOf(3, 4, 5), subArray.toIntArray())
}

5. Using the copyOfRange() Method

Another way to achieve the same objective is to utilize the copyOfRange() function, which involves specifying the beginning and ending positions and retrieving a subarray that exists between those positions. Unlike the other methods we’ve looked at which were inclusive of the end of the range, this function is exclusive of the end of the range, which means it will take elements up to but not including the specified end:

@Test
fun `using copyOfRange() method`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = array.copyOfRange(2, 5)
    assertArrayEquals(intArrayOf(3, 4, 5), subArray.toIntArray())
}

6. Using the filterIndexed() Method

The remaining approaches involve using a List because the methods we’ll use will achieve the goal but will return a List. So, we’ll use the toTypedArray() method to convert the List back to a new Array.

We can explore another effective technique by using the filterIndexed() approach. This method requires a predicate function that accepts the index of each Array element and the element itself. Once the predicate function is applied, the array is filtered to only contain the elements that meet the criteria. In this case, we’ll look for indices within the range we want for the subarray:

@Test
fun `using filterIndexed() method`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = array.filterIndexed { index, _ -> index in 2..4 }.toTypedArray()
    assertArrayEquals(intArrayOf(3, 4, 5), subArray.toIntArray())
}

It’s important to note that when using this approach, we don’t have to examine the array elements to extract the subarray. That’s why we use an underscore in our predicate function – it denotes an expected, unused parameter.

7. Using the drop() and take() Methods

We can trim the Array ourselves with the drop() and take() Array methods. With the drop() method, we can create a new Array that contains all the elements of the original Array except for the first n elements, where n is the number passed to the drop() method. Similarly, the take() method generates a new Array that contains the first n elements of the original Array. By chaining these methods together, we can extract a subarray that falls between two specific positions:

@Test
fun `using drop() and take() methods`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = array.drop(2).take(3).toTypedArray()
    assertArrayEquals(intArrayOf(3, 4, 5), subArray.toIntArray())
}

8. Using the subList() Method

We can also get a subarray of an array between given positions by using the subList() method, which returns the elements in a given range. Finally, it is worth mentioning that the range we provide to subList() is exclusive of the end of the range as well, like the copyOfRange() method:

@Test
fun `using subList() method`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = array.toList().subList(2, 5).toTypedArray()
    assertArrayEquals(intArrayOf(3, 4, 5), subArray.toIntArray())
}

9. Using the map() Method

The map() function provides another simple approach to obtaining a subarray of an Array that lies within specified indices:

@Test
fun `using map() method`() {
    val array = arrayOf(1, 2, 3, 4, 5, 6)
    val subArray = (2..4)
        .map { i: Int -> array[i] }
        .toTypedArray()
    assertArrayEquals(intArrayOf(3, 4, 5), subArray.toIntArray())
}

10. Conclusion

In this article, we’ve explored different ways to carve a subarray from an Array specified by given indices. Furthermore, by using these methods and writing unit tests, we can ensure that our code works as expected and produces accurate results.

As always, the code samples and relevant test cases pertaining to this article can be found over on GitHub.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.