Home > OS >  Kotlin How to ,,deep" copy array so I have two identical arrays but they are referencing differ
Kotlin How to ,,deep" copy array so I have two identical arrays but they are referencing differ

Time:11-18

I need to iterate over an array and change it's objects but I still need to reference the original array so that is why I need copy of the original array to change it's objects and then after completion of my operations I want to change the original array into the (copied) changed one. The size and objects are going to be the same but their values are going to change.

Thank you very much for your time and help in advance.

My problem is: when I copy the original array both copy and original are referencing the same locations in the memory so the state of the object changes and my code cannot complete it's tasks correctly. How can I copy an array so the copy references another locations in the memory but with identical objects?

Simple var copyArray = originalArray obviously doesn't work. I searched the web thorougly and I couldn't find exact answer to my problem in Kotlin.

CodePudding user response:

Option 1: Since your object only has one level of properties, a shallow copy is as effective as a deep copy. If it had more than one level you could still use copy() method but would have to specify explicitly how to copy each specific property.

val arrayOfArrays2 = arrayOfArrays.map { arrayOfCells -> arrayOfCells.map { it.copy() }  }

Full code:

fun main() {
    val cell1 = Cell(true)
    val cell2 = Cell(false)
    val arrayA = arrayOf(cell1, cell2)

    val arrayOfArrays = arrayOf(arrayA, arrayA)
    val arrayOfArrays2 = arrayOfArrays.map { arrayOfCells -> arrayOfCells.map { it.copy() }  }

    arrayOfArrays[0][0].isAlive = false;

    arrayOfArrays.forEach { it.forEach { println("ArrayA: $it") } }
    println()
    arrayOfArrays2.forEach { it.forEach { println("ArrayB: $it") } }
}

Which results in:

ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)

ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)

Option 2: You can serialize and deserialize the object.

Add the following dependency to build.gradle:

implementation 'com.google.code.gson:gson:2.9.0'

Make a deepCopy function inside your cell class:

import com.google.gson.Gson

data class Cell(
    var isAlive: Boolean
) {
    fun deepCopy(): Cell {
        val json = Gson().toJson(this)
        return Gson().fromJson(json, Cell::class.java)
    }
}

And code to test it out with:

fun main() {
    val cell1 = Cell(true)
    val cell2 = Cell(false)
    val arrayA = arrayOf(cell1, cell2)
    val arrayB = arrayA.map { it.deepCopy() }.toTypedArray()
    cell1.isAlive = false
    println(arrayA.contentToString())
    println(arrayB.contentToString())
}

Output:

[Cell(isAlive=false), Cell(isAlive=false)]
[Cell(isAlive=true), Cell(isAlive=false)]

Also, since you have a 2D array:

fun main() {
    val cell1 = Cell(true)
    val cell2 = Cell(false)
    val arrayA = arrayOf(cell1, cell2)

    val arrayOfArrays = arrayOf(arrayA, arrayA)
    val arrayOfArrays2 = arrayOfArrays.map { arrayOfCells -> arrayOfCells.map { it.deepCopy() } }.toTypedArray()

    arrayOfArrays[0][0].isAlive = false;

    arrayOfArrays.forEach { it.forEach { println("ArrayA: $it") } }
    println()
    arrayOfArrays2.forEach { it.forEach { println("ArrayB: $it") } }
}

Which results in:

ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)
ArrayA: Cell(isAlive=false)

ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
ArrayB: Cell(isAlive=true)
ArrayB: Cell(isAlive=false)
  • Related