Combine collections

How To Combine Collections in Kotlin

In this article we will show you different ways you can use to combine collections in Kotlin. Kotlin provides methods to make our lives easier in different situations like when we need to learn how to join two lists in Kotlin or when we need to merge two lists with alternating values.

In general these methods can be useful when we want the elements of multiple collections combined into a single collection, either entirely or partially. Let’s see how!

+ operator (plus)

Kotlin provides a way to overload operators and they’ve made use of it to override some of the operators for collections. If you are interested in how to overload operators you can check our article “How To Overload Operators in Kotlin”.

Operator overloading allows us to concatenate two collections by simply using the “+” operator. Let’s look at an example:

    @Test
    fun `should combine two collections into a single collection`() {

        val oneToFive = listOf(1, 2, 3, 4, 5)
        val sixToTen = listOf(6, 7, 8, 9, 10)

        val oneToTen = oneToFive + sixToTen

        assertThat(oneToTen).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    }

As you can see, the use of the “+” operator makes very easy to concatenate two different collections.

What if we wanted to combine more than two collections? We can actually use as many as we want!

    @Test
    fun `should combine three collections into a single collection`() {

        val oneToFive = listOf(1, 2, 3, 4, 5)
        val sixToTen = listOf(6, 7, 8, 9, 10)
        val elevenToFifteen = listOf(11, 12, 13, 14, 15)

        val oneToTen = oneToFive + sixToTen + elevenToFifteen

        assertThat(oneToTen).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
    }

What if we wanted to return just the unique elements between two collections? We can use union for that, let’s see how.

union

The union method returns a set containing the unique elements contained in both collections.

We are going to modify our previous example to show the difference between “+” operator and “union”.

    @Test
    fun `should combine two collections containing unique elements`() {

        val oneToSix = listOf(1, 2, 3, 4, 5, 6)
        val fourToTen = listOf(4, 5, 6, 7, 8, 9, 10)

        val oneToTen = oneToSix.union(fourToTen)

        assertThat(oneToTen).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    }

In this test we are creating two collections that overlap in three numbers (4, 5 and 6). If we used “+” operator with these two collections, we’ll get a list containing [1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9, 10] with a total of 13 elements.

On the other hand, when we use union, we get a Set containing just the unique elements between 1 and 10.

We are going to increase the complexity a bit more now, what if we want to return just the elements contained ONLY in one of the collections? Kotlin makes that very easy for us too! Let’s present the “-” operator for collections.

“-” operator (minus)

The minus operator is overloaded for collections to be able to return the elements in the first collection that are not contained in the second collection.

We are going to reuse the test used in the previous example to show how “-” operator works.

    @Test
    fun `should return elements contained in the first collection only`() {

        val oneToSix = listOf(1, 2, 3, 4, 5, 6)
        val fourToTen = listOf(4, 5, 6, 7, 8, 9, 10)

        val oneToTen = oneToSix - fourToTen

        assertThat(oneToTen).containsExactly(1, 2, 3)
    }

As you can see, we now expect just the elements contained in the first collection. In this case, just 1, 2 and 3 are contained in the first collection but not in the second collection. This is quite straightforward, right?

The latest example would be the equivalent to a left join, could we do right join as well? Of course! You can also do it the other way around. If we check what elements are contained only in the second collection we have the following:

    @Test
    fun `should return elements contained in the second collection only`() {

        val oneToSix = listOf(1, 2, 3, 4, 5, 6)
        val fourToTen = listOf(4, 5, 6, 7, 8, 9, 10)

        val oneToTen = fourToTen - oneToSix

        assertThat(oneToTen).containsExactly(7, 8, 9, 10)
    }

We hope this makes sense to you.

It’s worth mentioning that “*” and “/” are not currently overloaded for collections, keep in mind that we are not doing arithmetic operations with the values in the elements of the collection. We just add or subtract elements (not their values) to build a new collection. Is the difference clear?

Now that we know how to get the elements included in one of the collections only, how can we get the elements contained in BOTH collections? Let me introduce you to the intersect method.

Combine collections in Kotlin - intersect
Combine Collections in Kotlin – Photo by Denys Nevozhai on Unsplash

intersect

The intersect method returns a new collection containing only the elements contained in both collections.

As usual, we will going through a simple example to understand it easily.

    @Test
    fun `should return elements contained in both collections`() {

        val oneToSix = listOf(1, 2, 3, 4, 5, 6)
        val fourToTen = listOf(4, 5, 6, 7, 8, 9, 10)

        val oneToTen = fourToTen.intersect(oneToSix)

        assertThat(oneToTen).containsExactly(4, 5, 6)
    }

As you can see, it is very simple to achieve this in Kotlin. We now have the elements contained in both collections, which are 4, 5 and 6.

Let’s see one more traditional way of combining two collections, addAll.

addAll

A more traditional way to combine collections is addAll, you have probably used it already in Java.

If we take the example we used for “+” operator, the result we’d expect should be identical. However, we don’t recommend using this method for two reasons we’ll explained shortly.

Let’s see how would it look like first:

@Test
fun `should combine two collections into a single collection using addAll`() {

val oneToFive = mutableListOf(1, 2, 3, 4, 5)
val sixToTen = listOf(6, 7, 8, 9, 10)

oneToFive.addAll(sixToTen)

assertThat(oneToFive).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
}

You will be able to notice two things. First of all, the first collection must be mutable. Why is that? Kotlin provides addXXX methods only in mutable collections because, and here comes the most important part, this method mutates the initial collection instead of returning a new collection. That’s why in our test we don’t assign the result to a new “result” collection as in the rest of the examples.

These are the two reasons why we don’t generally recommend using this method, mainly because mutability makes your code not safe. The only possible reason to consider using mutable collections is in those cases where we need to reduce object creation and garbage collection activity for performance reasons.

Conclusion

In this article we have seen the different ways to combine collections and how easy Kotlin makes our lives again by providing very useful methods to achieve these operations.

If you are interested in reading more Kotlin articles, you can find more of our Kotlin articles here.

That’s all from us today! We hope you’ve found our article interesting and hopefully enjoyed reading it.

Please follow us if you are interested in reading more of our articles. See you soon!