Як клонувати або скопіювати список у kotlin


102

Як скопіювати список у Котліні?

Я використовую

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

Чи є простіший спосіб?


1
Я думаю, що ваше рішення вже найпростіший спосіб, якщо вам не потрібно глибоке клонування.
Сердар Саманчіоглу

Відповіді:


145

Це чудово працює.

val selectedSeries = series.toMutableList()

6
val selectedSeries = series.toList()також працює, тому що закликає toMutableList()в його реалізації.
Flávio Faria

4
@ FlávioFaria тільки тестував це, ===і, скажімо toList(), не копіює колекцію, але toMutableList()так
Peppermint Paddy

3
@PeppermintPaddy Це робить копію, за винятком випадку порожніх списків. Якщо джерело порожнє, Iterable.toList()повертається emptyList(), який завжди повертає той самий (незмінний) об'єкт. Тож якщо ви тестуєте, emptyList()ви отримаєте той самий об’єкт назад.
Лоранс Гонсалвес

52
Мені особисто не подобається ця ідея ... Нічого в документі документів не toMutableList()повинно повернути новий екземпляр списку, якщо екземпляр, що викликає метод, вже є змінним списком.
BrunoJCM

4
це не є вдалою відповіддю, і, безумовно, не правильною, немає гарантії, що майбутні реалізації можуть змінитися, якщо не буде спеціально зафіксовано, що цей виклик методу завжди поверне нову копію.
Бхаргав

23

Можна використовувати

Список -> toList ()

Масив -> toArray ()

ArrayList -> toArray ()

MutableList -> toMutableList ()


Приклад:

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())

журнал друку:

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

14

Я можу придумати два альтернативних способи:

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

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

Оновлення: за допомогою нового двигуна Type Inference (включення в Kotlin 1.3) ми можемо опустити параметр загального типу в 1-му прикладі і мати це:

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

FYI. Спосіб включення нового Inference - це kotlinc -Xnew-inference ./SourceCode.ktкомандний рядок або kotlin { experimental { newInference 'enable'}Gradle. Щоб отримати докладнішу інформацію про новий тип виводу, перегляньте це відео: KotlinConf 2018 - Новий тип висновку та пов'язані з ним мовні особливості Світлани Ісакової , особливо "висновок для будівельників" у 30 "


слід розділити їх на 2 відповіді imho, оскільки я думаю, що перша правильна, але в останньому бракує певної краси.
Холгер Брандл

@Jacob Wu: Я здивувався, побачивши, що символ * у другому рішенні не спричинив помилку. Що це робить? Я здійснив пошук з "неоднаковим множенням", але нічого не знайшов.
Lensflare

1
@Lensflare * означає знищити масив в окремі елементи, наприклад mutableListOf (* [1, 2, 3]) означає mutableListOf (1, 2, 3), це як операція, протилежна vararg
Якоб Ву

1
@Jacob Wu: Дякую З вашою відповіддю я зміг з’ясувати, що оператор називається «оператором розповсюдження». Я бачу, як це допомагає, поєднуючи деякі параметри з масивом у список varargs. Але яку користь вона має у вашому прикладі? Це швидше чи щось? Або це ключ до забезпечення копіювання колекції?
Lensflare

@Lensflare Я думаю, що користь - це лише синтаксис - код короткий, і явного родового типу не потрібно (як у моєму 1-му прикладі). Позаду, я вважаю, що код складається для операцій масиву, тому продуктивність повинна бути однаковою.
Яків Ву


9

Ви можете використовувати надане розширення, Iterable.toMutableList()яке надасть вам новий список. На жаль, його підпис і документація припускають, що це означало , щоб гарантувати , що Iterableце List(так само , як toStringі багато інших to<type>методи). Ніщо не гарантує вам, що це буде новий список. Наприклад, додавання наступного рядка на початку розширення: if (this is List) return thisце законне поліпшення продуктивності (якщо воно справді покращує ефективність).

Крім того, через свою назву отриманий код не дуже зрозумілий.

Я вважаю за краще додати власне розширення, щоб бути впевненим у результаті та створити набагато більш чіткий код (як і у нас для масивів ):

fun <T> List<T>.copyOf(): List<T> {
    val original = this
    return mutableListOf<T>().apply { addAll(original) }
}

fun <T> List<T>.mutableCopyOf(): MutableList<T> {
    val original = this
    return mutableListOf<T>().apply { addAll(original) }
}

Зауважте, що addAllце найшвидший спосіб копіювання, оскільки він використовує нативні System.arraycopyпрограми для реалізаціїArrayList .

Також майте на увазі, що це дасть вам лише дрібну копію .


Мені подобається це рішення. Чи не повинно бути addAll(this@copyOf), бо thisвсередині applyбуде посилатися на новостворений порожній список? Або це, або mutableListOf<T>().also { it.addAll(this) }?
Франко Леон Токаліч

5

Для дрібної копії пропоную

.map{it}

Це буде працювати для багатьох типів колекцій.


1
Зауважте, що це не працює для Maps. Вона компілюється, але оскільки " ita" Map.Entry, а копія неглибока, у вас є однакові записи.
noamtm

1
@noamtm так, саме це я маю на увазі під дрібною копією. Цей метод ніколи не копіює записи. Він зробить лише копію колекції з тими ж записами. Карта тут нічого особливого.
Lensflare

2
Моя думка полягає в тому, що хоч і спокусливо використовувати його на картах, і він збирається і, здається, працює - він насправді не працює.
noamtm

4

Як і в Java:

Список:

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

Карта:

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

Якщо припустити, що ви орієнтовані на JVM (або Android); Я не впевнений, що він працює для інших цілей, оскільки він покладається на конструктори копій ArrayList і HashMap.


2

Я хотів би використовувати в toCollection()метод розширення :

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

Це створить новий, MutableListа потім додасть кожен елемент оригіналу до новоствореного списку.

Виведений тут тип буде MutableList<String>. Якщо ви не хочете викривати змінність цього нового списку, ви можете вказати тип явно як незмінний список:

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

0

Для простих списків є багато правильних рішень вище.

Однак це лише для неглибоких списків.

Наведена нижче функція працює для будь-яких двовимірних ArrayList. ArrayListна практиці еквівалентний MutableList. Цікаво, що він не працює при використанні явного MutableListтипу. Якщо вам потрібно більше габаритів, необхідно зробити більше функцій.

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
}

Демо для цілої матриці:

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])

це показує 12



-1

Спробуйте нижче код для копіювання списку в Котліні

arrayList2.addAll(arrayList1.filterNotNull())
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.