## 1. Overview

*List* is a pretty common collection type in Kotlin.

In this tutorial, we’ll learn how to compare two lists in Kotlin.

## 2. Introduction to the Problem

A *List* is an ordered collection of elements. Further, **a List can contain duplicate values**.

Therefore, when we’re talking about comparing two lists, depending on the requirement, there are a couple of scenarios in which we consider two lists are equal:

- Two lists have the same size, contain the same elements, and are in the same order.
- Two lists have the same size and contain the same elements. However, we don’t care about the order of the elements.

An example may explain it quickly. Let’s say we have a target list:

`private val targetList = listOf("one", "two", "three", "four", "five")`

As the code above shows, we have five elements in *targetList*.

Then, let’s create some more lists of different cases:

```
private val listExactlySame = listOf("one", "two", "three", "four", "five")
private val listInDiffSizeButWithSameElements = listOf("one", "two", "three", "four", "five", "five", "five")
private val listInDiffSizeAndElements = listOf("one", "two", "three", "four", "five", "five", "five", "I am a new element")
private val listInDiffOrder = listOf("two", "one", "three", "five", "four")
private val listInDiffElement = listOf("ONE", "two", "three", "four", "FIVE")
```

Next, let’s build methods to cover the two comparison scenarios we mentioned above to determine if these lists are the “same” as our *targetList*.

For simplicity, we’ll use unit test assertions to verify whether our comparison methods work as expected.

## 3. Comparing Elements and the Order

**In Kotlin, we use structural equality ( ==) to evaluate if both values are the same or equal**. This is the same as the

*equals()*method in Java.

Therefore, if *list1 == list2* is true, both lists have the same size and contain the same elements in exactly the same order.

Next, let’s test it with our lists:

```
targetList.let {
assertThat(listExactlySame == it).isTrue
assertThat(listInDiffOrder == it).isFalse
assertThat(listInDiffSizeButWithSameElements == it).isFalse
assertThat(listInDiffSizeAndElements == it).isFalse
assertThat(listInDiffElement == it).isFalse
}
```

As the code above shows, if we compare two lists using structural equality, only *listExactlySame* and *targetList* should be equal. If we run the test, it passes.

So,** == is the most straightforward way to compare two lists to see if they are equal**.

## 4. Compare Elements Ignoring the Order

When we’re facing the “ignoring order” requirement, some of us may come up with this idea: *list1.size() == list2.size() && list1.containsAll(list2) &&list2.containsAll(list1)*.

Indeed, this solves the problem. However, *List*‘s *containsAll* is an expensive method. As *List*‘s look-up costs *O(N)*. Thus, given that both lists have the same size, *list1.containsAll(list2)’s* cost is *O(N^2)*.

To get better performance, we can use *Set* to solve the problem. The lookup function on *HashSet* costs only *O(1)*. Therefore, we can solve the problem by first converting both lists to *HashSets* and then checking the structural equality of the two sets. The total cost will be *O(N)*.

Now that we understand what to do, the implementation won’t be a challenge at all:

```
fun <T> equalsIgnoreOrder(list1:List<T>, list2:List<T>) = list1.size == list2.size && list1.toSet() == list2.toSet()
```

**It’s worth mentioning that Kotlin’s List.toSet() function returns a LinkedHashSet object, which is a sub-type of HashSet.**

The implementation is pretty straightforward. However, to make the function call fluent, we can create an extension function on *List*:

`fun <T> List<T>.equalsIgnoreOrder(other: List<T>) = this.size == other.size && this.toSet() == other.toSet()`

In this way, the function call will look like *list1.equalsIgnoreOrder(list2)*.

Moreover, **as the extension function has only one parameter, we can add the infix notation to make the function call more easy-to-read**:

```
infix fun <T> List<T>.equalsIgnoreOrder(other: List<T>) = this.size == other.size && this.toSet() == other.toSet()
if (list1 equalsIgnoreOrder list2) ....
```

Now, let’s test it using our example lists:

```
targetList.let {
assertThat(listExactlySame equalsIgnoreOrder it).isTrue
assertThat(listInDiffOrder equalsIgnoreOrder it).isTrue
assertThat(listInDiffSizeButWithSameElements equalsIgnoreOrder it).isFalse
assertThat(listInDiffSizeAndElements equalsIgnoreOrder it).isFalse
assertThat(listInDiffElement equalsIgnoreOrder it).isFalse
}
```

As the assertions above show if we ignore the order of the elements, *listInDiffOrder* and *listExactlySame* should be equal to our *targetList*.

The test passes when we execute it. Therefore, our *equalsIgnoreOrder* function works as expected.

## 5. Conclusion

In this article, we’ve explored how to compare two *List* objects with or without checking the elements’ order.

Additionally, we’ve learned that using Kotlin’s extension function and infix notation can help write easy-to-read code.

As always, the complete source code used in the article can be found on GitHub.