64

Given some arrays in Kotlin

let a = arrayOf("first", "second")
val b = arrayOf("first", "second")
val c = arrayOf("1st", "2nd")

Are there built-in functions to the Kotlin std-lib that tests two arrays for (value) equality for each element?

Thus resulting in:

a.equals(b) // true
a.equals(c) // false

equals() is actually returning false in both cases, but maybe there are built-in functions to Kotlin that one could use?

There is the static function java.utils.Arrays.deepEquals(a.toTypedArray(), b.toTypedArray()) but I would rather prefer an instance method as it would work better with optionals.

Lars Blumberg
  • 19,326
  • 11
  • 90
  • 127

6 Answers6

66

In Kotlin 1.1 you can use contentEquals and contentDeepEquals to compare two arrays for structural equality. e.g.:

a contentEquals b // true
b contentEquals c // false

In Kotlin 1.0 there are no "built-in functions to the Kotlin std-lib that tests two arrays for (value) equality for each element."

"Arrays are always compared using equals(), as all other objects" (Feedback Request: Limitations on Data Classes | Kotlin Blog).

So a.equals(b) will only return true if a and b reference the same array.

You can, however, create your own "optionals"-friendly methods using extension functions. e.g.:

fun Array<*>.equalsArray(other: Array<*>) = Arrays.equals(this, other)
fun Array<*>.deepEqualsArray(other: Array<*>) = Arrays.deepEquals(this, other)

P.S. The comments on Feedback Request: Limitations on Data Classes | Kotlin Blog are worth a read as well, specifically comment 39364.

mfulton26
  • 29,956
  • 6
  • 64
  • 88
25

Kotlin 1.1 introduced extensions for comparing arrays by content: contentEquals and contentDeepEquals.

These extensions are infix, so you can use them the following way:

val areEqual = arr1 contentEquals arr2
Ilya
  • 21,871
  • 8
  • 73
  • 92
19

And if you want to compare contents of two Collections ignoring the order you can add this simple extension:

infix fun <T> Collection<T>.sameContentWith(collection: Collection<T>?)
    = collection?.let { this.size == it.size && this.containsAll(it) }

...and use it like this:

a = mutableListOf<String>()
b = mutableListOf<String>()

isListsHasSameContent = a sameContentWith b
Alexander Krol
  • 1,418
  • 15
  • 15
  • Awesome. This should be the accepted answer for collection (if not using array) – mochadwi Jun 03 '19 at 07:24
  • 3
    Watch out for edge condition; `listOf("a", "b", "b").sameContentWith(listOf("a", "a", "b"))` is true when it might be expected to return false. – dnault Sep 20 '21 at 20:02
  • @dnault thanks for mentioning this. well, looks like this works perfectly for Sets :) – Alexander Krol Sep 06 '22 at 20:08
  • 1
    `sameContentWith` unfortunately has even more errors. You can give elements into the left collection that aren't in the right collection, and even then `sameContentWith` might return true - for example in this case: `listOf("a", "b").sameContentWith(listOf("a", "a"))` – fjf2002 Jan 04 '23 at 14:33
5

For a simple equals (not deep equals!):

otherArray.size == array.size && otherArray.filter { !array.contains(it) }.isEmpty()

This code will compare the size and the items. The items are compared with .equals().

Kevin Robatel
  • 8,025
  • 3
  • 44
  • 57
2

In koltin if your array or ArrayList is type of a data Class you can simply compare array :a and array :b

like this

if(a == b)

it will return simple boolean if it matched all the value of both arrays, but if you are matching other-than data data Class then you can use this extension to compare it with single value

fun <T> Array<T>.isEqual(comparable: Array<T>): Boolean {
    var isChanged = true

    if (this.size == comparable.size) {
        for (index in 0 until comparable.size) {
            if (this[index] != comparable[index]) {
                isChanged = false
                break
            }
        }
    } else {
        isChanged = false
    }

    return isChanged
}

then you can use your array

    val a = arrayOf("first", "second")
    val b = arrayOf("first", "second")

    println(a.isEqual(b)) //true

    a[0] = "third"

    println(a.isEqual(b)) //false
Arbaz Pirwani
  • 935
  • 7
  • 22
0

Checking of Two ArrayList equality:

fun isArrayListEquals(
    list1: ArrayList<CustomItem>,
    list2: ArrayList<CustomItem>,
): Boolean {
    if (list1.size != list2.size) return false

    val hash1 = list1.map { it.hashCode() }.toSet()
    val hash2 = list2.map { it.hashCode() }.toSet()

    return (hash1.intersect(hash2)).size == hash1.size
}


import java.util.Objects;

public class CustomItem {
    private String id, title, key;

    // implement getter/setter here

    // Mandatory
    @Override
    public int hashCode() {
        return Objects.hash(id, title, key);
    }
}

Or Simple Solution:

fun isArrayListEquals(
    list1: ArrayList<CustomItem>,
    list2: ArrayList<CustomItem>,
): Boolean {
    val gson = Gson()
    val list1Str = gson.toJson(list1)
    val list2Str = gson.toJson(list2)
    return list1Str == list2Str
}
Ahamadullah Saikat
  • 4,437
  • 42
  • 39