Cara mengkloning atau menyalin daftar di kotlin

104

Bagaimana cara menyalin daftar di Kotlin?

saya menggunakan

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

Apakah ada cara yang lebih mudah?

Audi
sumber
1
Saya pikir solusi Anda sudah merupakan cara termudah, jika Anda tidak memerlukan kloning yang dalam.
Serdar Samancıoğlu

Jawaban:

147

Ini bekerja dengan baik.

val selectedSeries = series.toMutableList()
Audi
sumber
6
val selectedSeries = series.toList()juga berfungsi karena memanggil toMutableList()dalam implementasinya.
Flávio Faria
4
@ FlávioFaria baru saja mengujinya ===dan harus mengatakan toList()tidak menyalin koleksinya, tetapi toMutableList()melakukannya
Peppermint Paddy
3
@PeppermintPaddy Ini tidak copy, kecuali dalam kasus daftar kosong. Jika sumber kosong, Iterable.toList()kembalikan emptyList(), yang selalu mengembalikan objek yang sama (tidak dapat diubah). Jadi jika Anda menguji dengan emptyList()Anda akan mendapatkan kembali objek yang sama.
Laurence Gonsalves
52
Saya pribadi tidak menyukai gagasan ini ... Tidak ada dalam dokumen hibah yang toMutableList()akan mengembalikan contoh baru dari daftar jika contoh yang memanggil metode sudah daftar yang bisa berubah.
BrunoJCM
4
ini bukan jawaban yang bagus, dan jelas bukan jawaban yang benar, tidak ada jaminan bahwa implementasi di masa mendatang mungkin berubah, kecuali jika didokumentasikan secara khusus bahwa pemanggilan metode ini akan selalu mengembalikan salinan baru.
Bhargav
23

Kamu bisa memakai

Daftar -> toList ()

Array -> toArray ()

ArrayList -> toArray ()

MutableList -> toMutableList ()


Contoh:

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

cetak log:

array: 4
arrayCopy: 4
array after remove: 3
arrayCopy after remove: 4
Rasoul Miri
sumber
14

Saya dapat menemukan dua cara alternatif:

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

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

Pembaruan: dengan mesin Jenis Inferensi baru (ikut serta di Kotlin 1.3), Kita dapat menghilangkan parameter jenis umum pada contoh pertama dan memiliki ini:

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

FYI. Cara untuk mengikutsertakan Inferensi baru adalah kotlinc -Xnew-inference ./SourceCode.ktuntuk baris perintah, atau kotlin { experimental { newInference 'enable'}untuk Gradle. Untuk info lebih lanjut tentang Inferensi Jenis baru, lihat video ini: KotlinConf 2018 - Inferensi Jenis Baru dan Fitur Bahasa Terkait oleh Svetlana Isakova , terutama 'inferensi untuk pembangun' di 30 '

Jacob Wu
sumber
harus dibagi menjadi 2 jawaban imho, karena menurut saya yang pertama benar, tetapi yang terakhir kurang indah.
Holger Brandl
@ Jacob Wu: Saya terkejut melihat bahwa simbol * di solusi kedua tidak menghasilkan kesalahan. Apa fungsinya? Saya melakukan pencarian dengan "perkalian unary" tetapi tidak menemukan apa-apa.
Lensflare
1
@Lensflare * berarti menghancurkan array menjadi item terpisah, misalnya mutableListOf (* [1, 2, 3]) berarti mutableListOf (1, 2, 3), ini seperti operasi yang berlawanan dengan vararg
Jacob Wu
1
@Jacob Wu: Terima kasih. Dengan jawaban Anda, saya dapat mengetahui bahwa operator tersebut disebut "operator tersebar". Saya melihat bagaimana ini membantu dengan menggabungkan beberapa parameter dengan array ke dalam daftar varargs. Tetapi manfaat apa yang dimilikinya dalam contoh Anda? Apakah lebih cepat atau apa? Atau apakah itu kunci untuk memastikan bahwa koleksi tersebut disalin?
Lensflare
@Lensflare Saya pikir manfaatnya hanya sintaksnya - kodenya pendek, dan tidak diperlukan tipe generik eksplisit (seperti dalam contoh pertama saya). Di belakang layar, saya yakin kode tersebut dikompilasi ke operasi array, jadi kinerjanya harus sama.
Jacob Wu
10

Jika daftar Anda menyimpan kelas data kotlin , Anda bisa melakukan ini

selectedSeries = ArrayList(series.map { it.copy() })
Levon Petrosyan
sumber
9

Anda dapat menggunakan ekstensi Iterable.toMutableList()yang disediakan yang akan memberi Anda daftar baru. Sayangnya, seperti yang disarankan oleh tanda tangan dan dokumentasinya , ini dimaksudkan untuk memastikan bahwa an Iterableadalah List(seperti toStringdan banyak to<type>metode lainnya ). Tidak ada yang menjamin Anda bahwa ini akan menjadi daftar baru . Misalnya, menambahkan baris berikut di awal ekstensi: if (this is List) return thisadalah peningkatan kinerja yang sah (jika memang meningkatkan kinerja).

Juga, karena namanya, kode yang dihasilkan tidak terlalu jelas.

Saya lebih suka menambahkan ekstensi saya sendiri untuk memastikan hasilnya dan membuat kode yang jauh lebih jelas (seperti yang kita miliki untuk array ):

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

Perhatikan bahwa addAllini adalah cara tercepat untuk menyalin karena menggunakan native System.arraycopydalam implementasi ArrayList.

Juga, berhati-hatilah karena ini hanya akan memberi Anda salinan yang dangkal .

Tuan Codesalot
sumber
Saya suka solusi ini. Bukankah seharusnya begitu addAll(this@copyOf), karena thisinside applyakan mengacu pada daftar kosong yang baru dibuat? Apakah itu atau mutableListOf<T>().also { it.addAll(this) }?
Franko Leon Tokalić
5

Untuk salinan yang dangkal, saya sarankan

.map{it}

Itu akan berfungsi untuk banyak jenis koleksi.

Lensa suar
sumber
1
Perhatikan bahwa ini tidak berfungsi untuk Maps. Ini mengkompilasi, tetapi karena itadalah a Map.Entry, dan salinannya dangkal, Anda memiliki entri yang sama.
noamtm
1
@noamtm ya, itulah yang saya maksud dengan salinan dangkal. Metode ini tidak akan pernah menyalin entri. Ini hanya akan membuat salinan dari koleksi dengan entri yang sama. Peta tidak ada yang istimewa di sini.
Lensflare
2
Maksud saya adalah, meskipun tergoda untuk menggunakannya di peta juga, dan itu mengkompilasi dan tampaknya berfungsi - itu tidak benar-benar berfungsi.
noamtm
4

Seperti di Jawa:

Daftar:

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

Peta:

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

Dengan asumsi Anda menargetkan JVM (atau Android); Saya tidak yakin ini berfungsi untuk target lain, karena bergantung pada konstruktor salinan ArrayList dan HashMap.

noamtm
sumber
2

Saya akan menggunakan satu toCollection()metode ekstensi :

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

Ini akan membuat yang baru MutableListdan kemudian menambahkan setiap elemen asli ke daftar yang baru dibuat.

Jenis yang disimpulkan di sini adalah MutableList<String>. Jika Anda tidak ingin mengekspos mutabilitas daftar baru ini, Anda dapat mendeklarasikan tipe secara eksplisit sebagai daftar yang tidak dapat diubah:

val copy: List<String> = original.toCollection(mutableListOf())
Ben P.
sumber
0

Untuk daftar sederhana memiliki banyak solusi tepat di atas.

Namun, ini hanya untuk daftar yang dangkal.

Fungsi di bawah ini berfungsi untuk 2 dimensi apa pun ArrayList. ArrayListadalah, dalam praktiknya, setara dengan MutableList. Menariknya, ini tidak berfungsi saat menggunakan MutableListtipe eksplisit . Jika seseorang membutuhkan lebih banyak dimensi, itu perlu membuat lebih banyak fungsi.

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 untuk Matriks integer:

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

itu menunjukkan 12

Paulo Buchsbaum
sumber
0

Anda dapat menggunakan ArrayListkonstruktor:ArrayList(list)

Solomon Ucko
sumber
-1

Coba kode di bawah ini untuk menyalin daftar di Kotlin

arrayList2.addAll(arrayList1.filterNotNull())
Yyy
sumber