Adolf Dsilva
Adolf Dsilva

Reputation: 14340

How to clone or copy a list in kotlin

How to copy list in Kotlin?

I'm using

val selectedSeries = mutableListOf<String>()
selectedSeries.addAll(series)

Is there a easier way?

Upvotes: 250

Views: 182834

Answers (15)

Andrew S.
Andrew S.

Reputation: 922

IMHO the best and most idomatic way is use collection builders in new versions of Kotlin (1.6+)

   val shallowListCopy = buildList { addAll(list) }

Upvotes: 3

Sir Codesalot
Sir Codesalot

Reputation: 7283

You can use the provided extension Iterable.toMutableList() which will provide you with a new list. Unfortunately, as its signature and documentation suggest, it's meant to ensure that an Iterable is a List (just like toString and many other to<type> methods). Nothing guarantees you that it's going to be a new list. For instance, adding the following line at the beginning of the extension: if (this is List) return this is a legitimate performance improvement (if it indeed improves the performance).

Also, because of its name, the resulting code isn't very clear.

I prefer to add my own extension to be sure of the result and create a much more clear code (just like we have for arrays):

fun <T> List<T>.copyOf(): List<T> {
    return mutableListOf<T>().also { it.addAll(this) }
}

fun <T> List<T>.mutableCopyOf(): MutableList<T> {
    return mutableListOf<T>().also { it.addAll(this) }
}

Note that addAll is the fastest way to copy because it uses the native System.arraycopy in the implementation of ArrayList.

Also, beware that this will only give you a shallow copy.

EDIT:

You might want to use the more generic version:

fun <T> Collection<T>.copyOf(): Collection<T> {
    return mutableListOf<T>().also { it.addAll(this) }
}

fun <T> Collection<T>.mutableCopyOf(): MutableCollection<T> {
    return mutableListOf<T>().also { it.addAll(this) }
}

Upvotes: 19

Yasin Ege
Yasin Ege

Reputation: 723

var oldList: List<ClassA>?
val newList = oldList.map { it.copy() }

Upvotes: 5

Adam Noor
Adam Noor

Reputation: 139

After trying shallow copy, deep copy cloning and many more i found this solution surely it will work for you.

val iterator: Iterator<Object> = yourList.iterator()
        while (iterator.hasNext())
        newList.add(iterator.next().copy())

Upvotes: 1

A.Y.
A.Y.

Reputation: 398

val selectedSeries = listOf(*series.toTypedArray())

Upvotes: 3

Solomon Ucko
Solomon Ucko

Reputation: 6109

You can use the ArrayList constructor: ArrayList(list)

Upvotes: 10

noamtm
noamtm

Reputation: 12973

Just like in Java:

List:

    val list = mutableListOf("a", "b", "c")
    val list2 = ArrayList(list)

Map:

    val map = mutableMapOf("a" to 1, "b" to 2, "c" to 3)
    val map2 = HashMap(map)

Assuming you're targeting the JVM (or Android); I'm not sure it works for other targets, as it relies on the copy constructors of ArrayList and HashMap.

Upvotes: 21

Yyy
Yyy

Reputation: 2335

Try below code for copying list in Kotlin

arrayList2.addAll(arrayList1.filterNotNull())

Upvotes: -6

Paulo Buchsbaum
Paulo Buchsbaum

Reputation: 2659

For simple lists has many right solutions above.

However, it's just for shallows lists.

The below function works for any 2 dimensional ArrayList. ArrayList is, in practice, equivalent to MutableList. Interestingly it doesn't work when using explicit MutableList type. If one needs more dimensions, it's necessary make more functions.

fun <T>cloneMatrix(v:ArrayList<ArrayList<T>>):ArrayList<ArrayList<T>>{
  var MatrResult = ArrayList<ArrayList<T>>()
  for (i in v.indices) MatrResult.add(v[i].clone() as ArrayList<T>)
  return MatrResult
}

Demo for integer Matrix:

var mat = arrayListOf(arrayListOf<Int>(1,2),arrayListOf<Int>(3,12))
var mat2 = ArrayList<ArrayList<Int>>()
mat2 = cloneMatrix<Int>(mat)
mat2[1][1]=5
println(mat[1][1])

it shows 12

Upvotes: 0

Levon Petrosyan
Levon Petrosyan

Reputation: 9625

If your list is holding kotlin data class, you can do this

selectedSeries = ArrayList(series.map { it.copy() })

Upvotes: 54

Rasoul Miri
Rasoul Miri

Reputation: 12222

You can use

List -> toList()

Array -> toArray()

ArrayList -> toArray()

MutableList -> toMutableList()


Example:

val array = arrayListOf("1", "2", "3", "4")

val arrayCopy = array.toArray() // copy array to other array

Log.i("---> array " ,  array?.count().toString())
Log.i("---> arrayCopy " ,  arrayCopy?.count().toString())

array.removeAt(0) // remove first item in array 

Log.i("---> array after remove" ,  array?.count().toString())
Log.i("---> arrayCopy after remove" ,  arrayCopy?.count().toString())

print log:

array: 4
arrayCopy: 4
array after remove: 3
arrayCopy after remove: 4

Upvotes: 58

Ben P.
Ben P.

Reputation: 54204

I would use the toCollection() extension method:

val original = listOf("A", "B", "C")
val copy = original.toCollection(mutableListOf())

This will create a new MutableList and then add each element of the original to the newly-created list.

The inferred type here will be MutableList<String>. If you don't want to expose the mutability of this new list, you can declare the type explicitly as an immutable list:

val copy: List<String> = original.toCollection(mutableListOf())

Upvotes: 3

Adolf Dsilva
Adolf Dsilva

Reputation: 14340

This works fine.

val selectedSeries = series.toMutableList()

Upvotes: 300

Jacob Wu
Jacob Wu

Reputation: 908

I can come up with two alternative ways:

1. val selectedSeries = mutableListOf<String>().apply { addAll(series) }

2. val selectedSeries = mutableListOf(*series.toTypedArray())

Update: with the new Type Inference engine(opt-in in Kotlin 1.3), We can omit the generic type parameter in 1st example and have this:

1. val selectedSeries = mutableListOf().apply { addAll(series) }

FYI.The way to opt-in new Inference is kotlinc -Xnew-inference ./SourceCode.kt for command line, or kotlin { experimental { newInference 'enable'} for Gradle. For more info about the new Type Inference, check this video: KotlinConf 2018 - New Type Inference and Related Language Features by Svetlana Isakova, especially 'inference for builders' at 30'

Upvotes: 22

Lensflare
Lensflare

Reputation: 942

For a shallow copy, I suggest

.map{it}

That will work for many collection types.

Upvotes: 9

Related Questions