Come clonare o copiare un elenco in kotlin


104

Come copiare l'elenco in Kotlin?

sto usando

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

C'è un modo più semplice?


1
Penso che la tua soluzione sia già il modo più semplice, nel caso in cui non sia necessaria una clonazione profonda.
Serdar Samancıoğlu

Risposte:


147

Funziona bene.

val selectedSeries = series.toMutableList()

6
val selectedSeries = series.toList()funziona anche perché chiama toMutableList()nella sua implementazione.
Flávio Faria

4
@ FlávioFaria l'ha appena testato ===e devo dire toList()che non copia la raccolta, ma lo toMutableList()fa
Peppermint Paddy

3
@PeppermintPaddy Si fa copia, salvo nel caso di liste vuote. Se la sorgente è vuota, Iterable.toList()restituisce emptyList(), che restituisce sempre lo stesso oggetto (immutabile). Quindi, se provi con emptyList(), riavrai indietro lo stesso oggetto.
Laurence Gonsalves

52
Personalmente non mi piace questa idea ... Niente nei documenti garantisce che toMutableList()dovrebbe restituire una nuova istanza di un elenco se l'istanza che chiama il metodo è già un elenco modificabile.
BrunoJCM

4
questa non è una buona risposta, e sicuramente non quella giusta, non vi è alcuna garanzia che le implementazioni future possano cambiare, a meno che non sia specificamente documentato che questa chiamata al metodo restituirà sempre una nuova copia.
Bhargav

23

Puoi usare

List -> toList ()

Array -> toArray ()

ArrayList -> toArray ()

MutableList -> toMutableList ()


Esempio:

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

registro di stampa:

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

14

Posso trovare due modi alternativi:

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

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

Aggiornamento: con il nuovo motore di inferenza del tipo (opt-in in Kotlin 1.3), possiamo omettere il parametro di tipo generico nel 1 ° esempio e avere questo:

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

Cordiali saluti, il modo per attivare la nuova inferenza è kotlinc -Xnew-inference ./SourceCode.ktper la riga di comando o kotlin { experimental { newInference 'enable'}per Gradle. Per maggiori informazioni sulla nuova inferenza del tipo, guarda questo video: KotlinConf 2018 - Nuova inferenza del tipo e funzionalità del linguaggio correlato di Svetlana Isakova , in particolare 'inferenza per i costruttori' a 30 '


dovrebbe essere diviso in 2 risposte imho, poiché penso che la prima sia corretta, ma la seconda manca di bellezza.
Holger Brandl

@ Jacob Wu: sono stato sorpreso di vedere che il simbolo * nella seconda soluzione non ha prodotto un errore. Che cosa fa? Ho fatto una ricerca con "moltiplicazione unaria" ma non ho trovato nulla.
Lensflare

1
@Lensflare * significa distruggere un array in elementi separati, ad esempio mutableListOf (* [1, 2, 3]) significa mutableListOf (1, 2, 3), è come l'operazione opposta a vararg
Jacob Wu

1
@ Jacob Wu: Grazie. Con la tua risposta, ho potuto scoprire che l'operatore si chiama "spread operator". Vedo come aiuta combinando alcuni parametri con un array in un elenco di vararg. Ma che vantaggio ha nel tuo esempio? È più veloce o qualcosa del genere? O è la chiave per garantire che la raccolta venga copiata?
Lensflare

@Lensflare Penso che il vantaggio sia solo la sintassi: il codice è breve e non è richiesto alcun tipo generico esplicito (come nel mio primo esempio). Dietro le quinte, credo che il codice sia compilato per operazioni di array, quindi le prestazioni dovrebbero essere le stesse.
Jacob Wu


9

Puoi utilizzare l'estensione fornita Iterable.toMutableList()che ti fornirà un nuovo elenco. Sfortunatamente, come suggeriscono la sua firma e la documentazione , ha lo scopo di garantire che an Iterablesia a List(proprio come toStringe molti altri to<type>metodi). Niente ti garantisce che sarà una nuova lista. Ad esempio, l'aggiunta della seguente riga all'inizio dell'estensione: if (this is List) return thisè un legittimo miglioramento delle prestazioni (se effettivamente migliora le prestazioni).

Inoltre, a causa del suo nome, il codice risultante non è molto chiaro.

Preferisco aggiungere la mia estensione per essere sicuro del risultato e creare un codice molto più chiaro (proprio come abbiamo per gli 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) }
}

Nota che addAllè il modo più veloce per copiare perché utilizza il nativo System.arraycopynell'implementazione di ArrayList.

Inoltre, fai attenzione che questo ti darà solo una copia superficiale .


Mi piace questa soluzione. Non dovrebbe essere addAll(this@copyOf), perché thisall'interno applyfarà riferimento alla lista vuota appena creata? O quello o mutableListOf<T>().also { it.addAll(this) }?
Franko Leon Tokalić

5

Per una copia superficiale, suggerisco

.map{it}

Funzionerà per molti tipi di raccolta.


1
Nota che non funziona per Maps. Viene compilato, ma poiché itè a Map.Entrye la copia è superficiale, hai le stesse voci.
noamtm

1
@noamtm sì, questo è ciò che intendo con copia superficiale. Questo metodo non copierà mai le voci. Farà solo una copia della collezione con le stesse voci. La mappa non è niente di speciale qui.
Lensflare

2
Il punto è che, anche se si è tentati di usarlo anche sulle mappe, si compila e sembra funzionare, non funziona davvero.
noamtm

4

Proprio come in Java:

Elenco:

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

Carta geografica:

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

Supponendo che tu stia prendendo di mira la JVM (o Android); Non sono sicuro che funzioni per altri obiettivi, poiché si basa sui costruttori di copia di ArrayList e HashMap.


2

Userei il toCollection()metodo di estensione :

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

Questo creerà un nuovo MutableListe quindi aggiungerà ogni elemento dell'originale all'elenco appena creato.

Il tipo dedotto qui sarà MutableList<String>. Se non vuoi esporre la mutabilità di questo nuovo elenco, puoi dichiarare il tipo esplicitamente come un elenco immutabile:

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

0

Per elenchi semplici ha molte soluzioni giuste sopra.

Tuttavia, è solo per gli elenchi dei fondali bassi.

La funzione seguente funziona per qualsiasi bidimensionale ArrayList. ArrayListè, in pratica, equivalente a MutableList. È interessante notare che non funziona quando si utilizza il MutableListtipo esplicito . Se sono necessarie più dimensioni, è necessario creare più funzioni.

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 per matrice intera:

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

mostra 12



-1

Prova sotto il codice per copiare l'elenco in Kotlin

arrayList2.addAll(arrayList1.filterNotNull())
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.