nashihu
nashihu

Reputation: 849

How to clone or copy a 2d list in kotlin

following from here

below provided for the test case

@Test
fun testKotlinArrayCopy() {

    data class Person(val name: String, var friends: List<Person>, var isHungry: Boolean = false)

    val okyFriends = listOf(
        Person(name = "Billy", friends = listOf()),
    )

    val peopleAtBlock1 : ArrayList<Person> = arrayListOf(
        Person(name = "Oky", friends = okyFriends),
    )

    val peopleAtBlock2 : ArrayList<Person>  = ArrayList(peopleAtBlock1.toMutableList())


    peopleAtBlock1[0].friends[0].isHungry = true
    
    // here i expect variable peopleAtBlock2 doesn't changed 
    // because i just change the peopleAtBlock1 only
    assertFalse(peopleAtBlock1[0] == peopleAtBlock2[0])
    
}

when i run the test it fails because the peopleAtBlock2 changed unexpectedly caused by this code

peopleAtBlock1[0].friends[0].isHungry = true

i want to keep value of peopleAtBlock2 is not changed, how do i do that?

thanks

EDIT:

i have follow answer here using

fun Array<BooleanArray>.copy() = map { it.clone() }.toTypedArray()

converted to my case, the function would be

fun ArrayList<Person>.copy2() = map { it.copy() }.toTypedArray()

but still doesn't work

please check my repl for running in cloud if you dont have kotlin

Upvotes: 1

Views: 383

Answers (2)

IR42
IR42

Reputation: 9692

fun Person.deepCopy(): Person = copy(friends = friends.map { it.deepCopy() })

val peopleAtBlock2 = peopleAtBlock1.map { it.deepCopy() }

Upvotes: 0

mightyWOZ
mightyWOZ

Reputation: 8345

In your case peopleAtBlock2 is a shallow copy of peopleAtBlock1, which means they reference the same objects. so when you change value of an object in peopleAtBlock1, its reflected in peopleAtBlock2 also.

In order to solve this you will have to create a deep copy of peopleAtBlock1. recommended way to do this is to use serialization. that is first you serialize the original data and then create a copy by de serializing.

there are better ways of doing this but a quick and easy way is to use JSON serialization, which can be done by following the below steps

First add dependency for Gson in your project as

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

Now move Person class outside the function, Gson doesn't work with local classes

Finally you can create a deep copy as

val type = object : TypeToken<ArrayList<Person>>(){}.type
val json = Gson().toJson(peopleAtBlock1, type)
val peopleAtBlock2 = Gson().fromJson<ArrayList<Person>>(json, type)

Upvotes: 1

Related Questions