1. Overview
In this tutorial, we’ll learn how to do equality checks for arrays in Kotlin.
2. Equality
There are two kinds of equality in Kotlin – namely, referential and structural equality. Further, we can use the === operator to check for referential equality and the == operator to check for structural equality.
Let’s define two arrays named first and second with the same values, and later define the third array that points to the same object as the first array:
val first = arrayOf("java", "python", "kotlin")
val second = arrayOf("java", "python", "kotlin")
val third = first
Now, let’s check for referential equality among these arrays:
Assertions.assertTrue(first === third)
Assertions.assertFalse(first === second)
Assertions.assertFalse(second === third)
Next, let’s check for structural equality among these arrays:
Assertions.assertTrue(first == third)
Assertions.assertFalse(first == second)
Assertions.assertFalse(second == third)
First, we must notice that although the first and second arrays are structurally equal, the == operator fails to demonstrate the expected behavior for checking them structurally.
In the following sections, we’ll explore how we can do the structural equality checks for arrays in Kotlin.
3. contentEquals Function
The contentEquals function is an infix function in Kotlin that can be used to make a structural comparison of arrays.
Let’s use the same arrays, namely first, second, and third, as we did earlier, and see the contentEquals function in action:
val first = arrayOf("java", "python", "kotlin")
val second = arrayOf("java", "python", "kotlin")
val third = first
Assertions.assertTrue(first contentEquals third)
Assertions.assertTrue(first contentEquals second)
Assertions.assertTrue(second contentEquals third)
As expected, we can see that with the contentEquals function, we can assert that all three arrays are structurally the same.
Next, let’s take a scenario where we have nested arrays – r1, r2, and r3:
val r1 = arrayOf(arrayOf("R1", "R2"), arrayOf("R3", "R4"))
val r2 = arrayOf(arrayOf("R1", "R2"), arrayOf("R3", "R4"))
val r3 = r1
Now, we’ll see that there is a limitation of the contentEquals function as it doesn’t make a comprehensive structural comparison of these nested arrays:
Assertions.assertTrue(r1 contentEquals r3)
Assertions.assertFalse(r1 contentEquals r2)
Assertions.assertFalse(r2 contentEquals r3)
4. contentDeepEquals Function
Kotlin offers the contentDeepEquals infix function to solve the structural equality comparison limitation of the contentEquals function in the case of the nested arrays.
Let’s compare the same set of nested arrays using the contentDeepEquals function:
val r1 = arrayOf(arrayOf("R1", "R2"), arrayOf("R3", "R4"))
val r2 = arrayOf(arrayOf("R1", "R2"), arrayOf("R3", "R4"))
val r3 = r1
Assertions.assertTrue(r1 contentDeepEquals r3)
Assertions.assertTrue(r1 contentDeepEquals r2)
Assertions.assertTrue(r2 contentDeepEquals r3)
As expected, we can see that the structural equality of the three nested arrays is confirmed.
5. Array of User-Defined Objects
So far, we’ve seen array comparisons for String values. Now, let’s go ahead and expand our understanding to compare arrays that contain user-defined objects.
Let’s define a Person class and initialize two arrays that contain instances of the Person class:
class Person (var name: String?, var age: Int?)
val first = arrayOf(Person("John", 20), Person("Mary", 15))
val second = arrayOf(Person("John", 20), Person("Mary", 15))
For such scenarios, the contentEquals function won’t be able to make a structural comparison of the arrays:
Assertions.assertFalse(first contentEquals second)
That’s because we haven’t defined the equals() method in the Person class, and as a result, the contentEquals function is, by default, doing a referential equality check.
We can solve this problem by defining the Person class as a data class:
data class Person (var name: String?, var age: Int?)
val first = arrayOf(Person("John", 20), Person("Mary", 15))
val second = arrayOf(Person("John", 20), Person("Mary", 15))
Assertions.assertTrue(first contentEquals second)
As a data class inherently defines the equals() method for value comparison, we can assert that the first and second arrays containing objects of Person type are structurally equal.
Moreover, we can also validate the structural equality for nested arrays holding objects of Person type using the contentDeepEquals function:
data class Person (var name: String?, var age: Int?)
val p1 = arrayOf(arrayOf(Person("John", 20), Person("Mary", 15)))
val p2 = arrayOf(arrayOf(Person("John", 20), Person("Mary", 15)))
Assertions.assertTrue(p1 contentDeepEquals p2)
6. Conclusion
In this article, we built an understanding of how to do equality checks for one-dimensional and nested arrays in Kotlin.
As always, the source code is available over on GitHub.