226

How to copy list in Kotlin?

I'm using

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

Is there a easier way?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Adolf Dsilva
  • 13,092
  • 8
  • 34
  • 45
  • 1
    I think your solution is already the easiest way, in case you don't need deep cloning. – Serdar Samancıoğlu Apr 18 '19 at 12:24
  • Copying a list just copies references to items. Items themselves won't clone. Don't forget to clone items during copying lists if you wish to have deep cloned lists. – CoolMind Oct 15 '20 at 07:36

15 Answers15

276

This works fine.

val selectedSeries = series.toMutableList()
Adolf Dsilva
  • 13,092
  • 8
  • 34
  • 45
  • 14
    `val selectedSeries = series.toList()` also works because it calls `toMutableList()` in its implementation. – Flávio Faria Feb 01 '18 at 20:19
  • 8
    @FlávioFaria just tested it with `===` and have to say `toList()` doesn't copy the collection, but `toMutableList()` does – Peppermint Paddy Apr 02 '18 at 11:27
  • 5
    @PeppermintPaddy It *does* copy, except in the case of empty lists. If the source is empty, `Iterable.toList()` returns`emptyList()`, which always returns the same (immutable) object. So if you test with `emptyList()` you'll get the same object back. – Laurence Gonsalves Apr 26 '18 at 22:06
  • 9
    this is not a good answer, and definitely not the right one, there is no guarantee that future implementations might change, unless its specifically documented that this method call will always return a new copy. – Bhargav Jun 12 '18 at 09:37
  • 10
    @BrunoJCM, that's not the case anymore. The Kotlin docs state that `toMutableList()` returns a *new* list, "Returns a new MutableList filled with all elements of this collection.". – Pär Nils Amsen Sep 08 '20 at 05:58
  • 1
    @PärNilsAmsen Verified what you stated is valid! Once contents changed, the two mutablelist will have a different hash. https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS40LjAiLCJwbGF0Zm9ybSI6ImphdmEiLCJhcmdzIjoiIiwianNDb2RlIjoiIiwibm9uZU1hcmtlcnMiOnRydWUsInRoZW1lIjoiaWRlYSIsImNvZGUiOiIvKipcbiAqIFlvdSBjYW4gZWRpdCwgcnVuLCBhbmQgc2hhcmUgdGhpcyBjb2RlLiBcbiAqIHBsYXkua290bGlubGFuZy5vcmcgXG4gKi9cblxuZnVuIG1haW4oKSB7XG4gICAgdmFsIGEgPSBtdXRhYmxlTGlzdE9mPEludD4oMSlcbiAgICB2YWwgYiA9IGEudG9NdXRhYmxlTGlzdCgpXG4gICAgYS5hZGQoMilcbiAgICBwcmludGxuKGEuaGFzaENvZGUoKSlcbiAgICBwcmludGxuKGIuaGFzaENvZGUoKSlcbn0ifQ== – Teng-pao Yu Sep 28 '20 at 10:28
  • This help also when you face the problem of overwriting some data class (List) item, just before to reassign the list make sure you're assigning a MutableList. – M.Fakhri May 31 '21 at 11:06
  • It’s still the least intuitive way ever if you want an _immutable_ snapshot of a _mutable_ collection to call something like `.toMutable…` on it. – Michael Piefel Dec 19 '22 at 07:44
54

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
Vitalii Dmitriev
  • 739
  • 1
  • 8
  • 18
Rasoul Miri
  • 11,234
  • 1
  • 68
  • 78
  • You're confusing Array with ArrayList. They're two very different things. In your code `array` is actually an `ArrayList` while `arrayCopy` is an `Array`. Their names are misleading. – k314159 Jun 13 '23 at 16:08
48

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

selectedSeries = ArrayList(series.map { it.copy() })
Levon Petrosyan
  • 8,815
  • 8
  • 54
  • 65
22

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'

Jacob Wu
  • 868
  • 9
  • 11
  • should be splitted into 2 answers imho, since I think the first one is correct, but the latter lacks some beauty. – Holger Brandl Aug 29 '18 at 08:37
  • @Jacob Wu: I was surprised to see that the * symbol in the second solution did not produce an error. What does it do? I did a search with "unary multiplication" but didn't find anything. – Lensflare Oct 24 '18 at 16:08
  • 1
    @Lensflare * means to destruct an array into separate items, e.g. mutableListOf( * [1, 2, 3] ) means mutableListOf(1, 2, 3), it's like the opposite operation to vararg – Jacob Wu Oct 25 '18 at 04:28
  • 1
    @Jacob Wu: Thank you. With your answer, I was able to find out that the operator is called "spread operator". I see how it helps by combining some parameters with an array into a varargs list. But what benefit does it have in your example? Is it faster or something? Or is it the key to ensure that the collection is copied? – Lensflare Oct 25 '18 at 08:26
  • @Lensflare I think the benefit is just the syntax - the code is short, and no explicit generic type is required(like in my 1st example). Behind the scene, I believe the code is compiled to array operations, so performance should be the same. – Jacob Wu Oct 25 '18 at 23:08
  • it's inefficient. The same as Java's `List.addAll` https://stackoverflow.com/questions/54381327/difference-between-arraylist-addalllist-and-new-arraylistlist-for-content Use https://stackoverflow.com/a/46846074/4548520 Test it https://try.kotlinlang.org/#/UserProjects/pllbim18v1vfa6one4i8l0hasj/497pnhfpsmvb73sn2378cv692d – user25 Jan 27 '19 at 00:17
  • Be careful about copying lists of non-primitive objects this way. The new list will contain the same objects as the old list, so changing an item in one will affect it in both lists. A true deep copy will also copy the list items. See https://stackoverflow.com/q/51480079/1015595. – Big McLargeHuge Nov 11 '19 at 21:46
20

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.

noamtm
  • 12,435
  • 15
  • 71
  • 107
19

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) }
}
Sir Codesalot
  • 7,045
  • 2
  • 50
  • 56
  • I like this solution. Shouldn't it be `addAll(this@copyOf)`, because `this` inside `apply` will refer to the newly created empty list? Either that or `mutableListOf().also { it.addAll(this) }`? – Franko Leon Tokalić Feb 19 '20 at 11:22
9

For a shallow copy, I suggest

.map{it}

That will work for many collection types.

Lensflare
  • 942
  • 8
  • 11
  • 1
    Note that it doesn't work for `Map`s. It compiles, but since the `it` is a `Map.Entry`, and the copy is shallow, you have the same entries. – noamtm Aug 29 '19 at 11:18
  • 1
    @noamtm yes, that is what I mean with shallow copy. This method will never copy the entries. It will only make a copy of the collection with the same entries. Map is nothing special here. – Lensflare Sep 10 '19 at 08:57
  • 2
    My point is, that even though it's tempting to use it on maps too, and it compiles and seems to work - it doesn't really work. – noamtm Sep 10 '19 at 11:32
7

You can use the ArrayList constructor: ArrayList(list)

Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45
4
var oldList: List<ClassA>?
val newList = oldList.map { it.copy() }
Yasin Ege
  • 605
  • 4
  • 14
3

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())
Ben P.
  • 52,661
  • 6
  • 95
  • 123
3
val selectedSeries = listOf(*series.toTypedArray())
A.Y.
  • 389
  • 3
  • 5
1

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())
Adam Noor
  • 101
  • 3
1

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

   val shallowListCopy = buildList { addAll(list) }
Andrew Sneck
  • 724
  • 9
  • 18
0

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

Paulo Buchsbaum
  • 2,471
  • 26
  • 29
-6

Try below code for copying list in Kotlin

arrayList2.addAll(arrayList1.filterNotNull())
Yyy
  • 2,285
  • 16
  • 29