Kotlin'de bir liste nasıl klonlanır veya kopyalanır


111

Kotlin'de liste nasıl kopyalanır?

kullanıyorum

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

Daha kolay bir yol var mı?


1
Derin klonlamaya ihtiyacınız yoksa çözümünüzün zaten en kolay yol olduğunu düşünüyorum.
Serdar Samancıoğlu

Bir listenin kopyalanması, yalnızca öğelere yapılan referansları kopyalar. Öğelerin kendileri klonlanmaz. Derin klonlanmış listeler istiyorsanız, listeleri kopyalarken öğeleri klonlamayı unutmayın.
CoolMind

Yanıtlar:


156

Bu iyi çalışıyor.

val selectedSeries = series.toMutableList()

6
val selectedSeries = series.toList()ayrıca çalışır çünkü toMutableList()uygulanmasını çağırır .
Flávio Faria

4
@ FlávioFaria az önce test etti ===ve toList()koleksiyonu kopyalamadığını söylemeliyim , ama toMutableList()yapıyor
Peppermint Paddy

3
@PeppermintPaddy Boş listeler haricinde kopyalama yapar . Kaynak boş ise, Iterable.toList()döner emptyList()her zaman aynı (iletmenin) nesnesi geri döndürür. Yani eğer test emptyList()ederseniz aynı nesneyi geri alırsınız.
Laurence Gonsalves

4
bu iyi bir cevap değildir ve kesinlikle doğru olanı değildir, bu yöntem çağrısının her zaman yeni bir kopya döndüreceği özel olarak belgelenmedikçe, gelecekteki uygulamaların değişebileceğinin garantisi yoktur.
Bhargav

1
@BrunoJCM, artık durum böyle değil. Kotlin belgeleri , yeni bir liste toMutableList()döndüren durumu , "Bu koleksiyonun tüm öğeleriyle dolu yeni bir MutableList döndürür."
Pär Nils Amsen

26

Kullanabilirsiniz

Liste -> toList ()

Dizi -> toArray ()

ArrayList -> toArray ()

MutableList -> toMutableList ()


Misal:

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

yazdırma günlüğü:

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

16

İki alternatif yol bulabilirim:

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

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

Güncelleme: Yeni Type Inference motoru ile (Kotlin 1.3'e dahil), 1. örnekte jenerik tip parametresini çıkarabiliriz ve buna sahip olabiliriz:

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

Bilginize: Yeni Çıkarımı etkinleştirmenin yolu kotlinc -Xnew-inference ./SourceCode.ktkomut satırı veya kotlin { experimental { newInference 'enable'}Gradle içindir. Yeni Tip Çıkarımı hakkında daha fazla bilgi için şu videoyu izleyin: KotlinConf 2018 - Svetlana Isakova'dan Yeni Tip Çıkarımı ve İlgili Dil Özellikleri , özellikle 30'da 'inşaatçılar için çıkarım'


Birincisinin doğru olduğunu düşündüğüm için iki yanıta bölünmeli, ancak ikincisi biraz güzelliğe sahip değil.
Holger Brandl

@Jacob Wu: İkinci çözümdeki * sembolünün bir hata vermediğini görünce şaşırdım. Bu ne işe yarıyor? "Tekli çarpma" ile arama yaptım ama hiçbir şey bulamadım.
Lensflare

1
@Lensflare *, bir diziyi ayrı öğelere ayırmak anlamına gelir, örneğin mutableListOf (* [1, 2, 3]), mutableListOf (1, 2, 3) anlamına gelir, bu, vararg'ın tam tersi bir işlemdir
Jacob Wu,

1
@Jacob Wu: Teşekkür ederim. Cevabınızla, operatörün "yayılma operatörü" olarak adlandırıldığını öğrendim. Bazı parametreleri bir dizi ile bir varargs listesi içinde birleştirmenin nasıl yardımcı olduğunu görüyorum. Peki sizin örneğinizde ne gibi faydalar var? Daha hızlı falan mı? Yoksa koleksiyonun kopyalanmasını sağlamanın anahtarı mı?
Lensflare

@Lensflare Yararının sadece sözdizimi olduğunu düşünüyorum - kod kısadır ve açık bir genel tür gerekmez (1. örneğimdeki gibi). Sahnenin arkasında, kodun dizi işlemlerine göre derlendiğine inanıyorum, bu nedenle performans aynı olmalıdır.
Jacob Wu


9

Size Iterable.toMutableList()yeni bir liste sağlayacak olan sağlanan uzantıyı kullanabilirsiniz . Ne yazık ki, imzası ve belgelerinin önerdiği gibi, an'ın Iterablea List(aynı toStringve diğer birçok to<type>yöntem gibi) olduğundan emin olmak içindir . Hiçbir şey size yeni bir liste olacağını garanti etmez . Örneğin, uzantının başına aşağıdaki satırı eklemek: if (this is List) return thismeşru bir performans iyileştirmesidir (eğer gerçekten performansı iyileştiriyorsa).

Ayrıca, adı nedeniyle ortaya çıkan kod çok net değildir.

Sonuçtan emin olmak ve çok daha net bir kod oluşturmak için kendi uzantımı eklemeyi tercih ediyorum (tıpkı diziler için olduğu gibi ):

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

Not addAllo yerli kullandığı için kopyalamak için en hızlı yoldur System.arraycopyuygulanmasında ArrayList.

Ayrıca, bunun size yalnızca sığ bir kopya vereceğine dikkat edin .


Bu çözümü beğendim. Olması gerekmiyor addAll(this@copyOf), çünkü thisiçeride applyyeni oluşturulan boş listeye atıfta bulunulacak mı? Ya öyle mutableListOf<T>().also { it.addAll(this) }mi?
Franko Leon Tokalić

5

Sığ bir kopya için öneririm

.map{it}

Bu, birçok koleksiyon türü için işe yarayacak.


1
MapS için çalışmadığını unutmayın . Derler, ancak ita Map.Entryolduğu ve kopya sığ olduğu için, aynı girişlere sahipsiniz.
noamtm

1
@noamtm evet, sığ kopya ile bunu kastediyorum. Bu yöntem asla girişleri kopyalamaz. Koleksiyonun yalnızca aynı girdilere sahip bir kopyasını oluşturacaktır. Harita burada özel bir şey değil.
Lensflare

2
Demek istediğim, onu haritalarda kullanmak cazip gelse de derliyor ve işe yarıyor gibi görünse de - gerçekten işe yaramıyor.
noamtm

4

Tıpkı Java'da olduğu gibi:

Liste:

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

Harita:

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

JVM'yi (veya Android'i) hedeflediğinizi varsayarsak; Diğer hedefler için çalıştığından emin değilim, çünkü ArrayList ve HashMap'in kopya yapıcılarına dayanıyor.


2

Ben kullanacağı uzatma yöntemi :toCollection()

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

Bu, yeni bir tane oluşturacak MutableListve ardından orijinalin her bir öğesini yeni oluşturulan listeye ekleyecektir.

Buradaki çıkarsama türü olacaktır MutableList<String>. Bu yeni listenin değişkenliğini ortaya çıkarmak istemiyorsanız, türü açıkça değişmez bir liste olarak bildirebilirsiniz:

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


0

Basit listeler için yukarıda birçok doğru çözüm vardır.

Ancak, sadece sığ listeler içindir.

Aşağıdaki fonksiyon herhangi bir 2 boyutlu için çalışır ArrayList. ArrayListpratikte eşdeğerdir MutableList. İlginç bir şekilde, açık MutableListtip kullanıldığında işe yaramıyor . Daha fazla boyuta ihtiyaç varsa, daha fazla işlev yapmak gerekir.

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
}

Tamsayı Matrisi için demo:

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

gösteriyor 12


-2

Kotlin'de liste kopyalamak için aşağıdaki kodu deneyin

arrayList2.addAll(arrayList1.filterNotNull())
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.