Elenco di Kotlin mancante "aggiungi", "rimuovi", mappa mancante "put", ecc.?


197

In Java potremmo fare quanto segue

public class TempClass {
    List<Integer> myList = null;
    void doSomething() {
        myList = new ArrayList<>();
        myList.add(10);
        myList.remove(10);
    }
}

Ma se lo riscriviamo a Kotlin direttamente come di seguito

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

Ho avuto l'errore di non trovare adde removefunzione dalla mia lista

Lavoro intorno al casting su ArrayList, ma è stranamente necessario lanciarlo, mentre in Java non è richiesto il casting. E questo sconfigge lo scopo di avere la classe astratta Elenco

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        (myList!! as ArrayList).add(10)
        (myList!! as ArrayList).remove(10)
    }
}

C'è un modo per usare List ma non ho bisogno di lanciarlo, come quello che si potrebbe fare in Java?


1
Solo un commento sul motivo per cui non è possibile eseguire myList = nulle successivamente su chiamata aggiungere senza !!. Puoi superarlo usando la lateinitparola chiave davanti alla tua proprietà in lateinit var myList: List<Int>questo modo : in questo modo non dovrai inizializzare immediatamente l'elenco, ma garantisci al compilatore che lo inizializzerai prima di utilizzare l'elenco la prima volta. È una soluzione più fluida, ma è una responsabilità per te come sviluppatore.
Darwind,

Risposte:


351

A differenza di molte lingue, Kotlin distingue tra collezioni mutabili e immutabili (elenchi, set, mappe, ecc.). Un controllo preciso su quando le raccolte possono essere modificate è utile per eliminare i bug e per progettare buone API.

https://kotlinlang.org/docs/reference/collections.html

Dovrai utilizzare un MutableListelenco.

class TempClass {
    var myList: MutableList<Int> = mutableListOf<Int>()
    fun doSomething() {
        // myList = ArrayList<Int>() // initializer is redundant
        myList.add(10)
        myList.remove(10)
    }
}

MutableList<Int> = arrayListOf() dovrebbe anche funzionare.


4
Risposta piacevole e ben scritta.
Prenderò la

6
Non è necessario rendere nullo l'elenco se lo si inizializza immediatamente. Ho modificato la tua risposta.
Kirill Rakhman,

37

Definizione di una raccolta Elenco in Kotlin in diversi modi:

  • Variabile immutabile con elenco immutabile (sola lettura):

    val users: List<User> = listOf( User("Tom", 32), User("John", 64) )


  • Variabile immutabile con elenco mutabile:

    val users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )

    o senza valore iniziale - elenco vuoto e senza tipo di variabile esplicito:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    • è possibile aggiungere elementi all'elenco:
      • users.add(anohterUser) o
      • users += anotherUser(sotto il cofano è users.add(anohterUser))


  • Variabile mutabile con elenco immutabile:

    var users: List<User> = listOf( User("Tom", 32), User("John", 64) )

    o senza valore iniziale - elenco vuoto e senza tipo di variabile esplicito:

    var users = emptyList<User>()
    • NOTA: è possibile aggiungere * elementi all'elenco:
      • users += anotherUser - * crea un nuovo ArrayList e lo assegna a users


  • Variabile mutabile con elenco mutabile:

    var users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )

    o senza valore iniziale - elenco vuoto e senza tipo di variabile esplicito:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    • NOTA: è possibile aggiungere elementi all'elenco:
      • users.add(anohterUser)
      • ma non usando users += anotherUser

        Errore: Kotlin: ambiguità degli operatori di assegnazione:
        divertimento pubblico Collection.plus (elemento: String): elenco definito in kotlin.collections
        @InlineSolo divertimento operatore in linea pubblico MutableCollection.plusAssign (elemento: String): unità definita in kotlin.collections


vedi anche: https://kotlinlang.org/docs/reference/collections.html


9

Concordare con tutte le risposte sopra riportate sull'uso di MutableList ma è anche possibile aggiungere / rimuovere dall'elenco e ottenere un nuovo elenco come di seguito.

val newListWithElement = existingList + listOf(element)
val newListMinusElement = existingList - listOf(element)

O

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)

8

Apparentemente, l'elenco predefinito di Kotlin è immutabile. Per avere un Elenco che potrebbe cambiare, si dovrebbe usare MutableList come di seguito

class TempClass {
    var myList: MutableList<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

Aggiornato Tuttavia, non è consigliabile utilizzare MutableList se non per una lista che si vuole veramente il cambiamento. Si riferisce a https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 per come la raccolta di sola lettura fornisce una migliore codifica.


Hai ragione sull'utilizzo MutableList, tuttavia l'inizializzazione con nullnon funzionerà. Sono consentite solo chiamate asserite sicure o non nulle su un destinatario nullable di tipo MutableList<Int>.
Fulvio,

Funziona da parte mia e non sono stati rilevati errori. Non ho bisogno di inizializzarlo a meno che quando ne ho bisogno quandodoSomething
Elye,

@Elye So che questa è una vecchia risposta e una domanda, ma usare lateinitinvece di rendere la lista nullable è il modo corretto di affrontare questo problema. Non ricordo se è lateinitstato aggiunto dall'inizio di Kotlin, ma questa è sicuramente la soluzione al giorno d'oggi per usarlo :-)
Darwind

5

In Kotlin devi usare MutableListo ArrayList.

Vediamo come funzionano i metodi MutableList:

var listNumbers: MutableList<Int> = mutableListOf(10, 15, 20)
// Result: 10, 15, 20

listNumbers.add(1000)
// Result: 10, 15, 20, 1000

listNumbers.add(1, 250)
// Result: 10, 250, 15, 20, 1000

listNumbers.removeAt(0)
// Result: 250, 15, 20, 1000

listNumbers.remove(20)
// Result: 250, 15, 1000

for (i in listNumbers) { 
    println(i) 
}

Vediamo come funzionano i metodi ArrayList:

var arrayNumbers: ArrayList<Int> = arrayListOf(1, 2, 3, 4, 5)
// Result: 1, 2, 3, 4, 5

arrayNumbers.add(20)
// Result: 1, 2, 3, 4, 5, 20

arrayNumbers.remove(1)
// Result: 2, 3, 4, 5, 20

arrayNumbers.clear()
// Result: Empty

for (j in arrayNumbers) { 
    println(j) 
}

4

Puoi farne uno nuovo come questo.

var list1 = ArrayList<Int>()
var list2  = list1.toMutableList()
list2.add(item)

Ora puoi usare list2, grazie.



2

Limitazione della mutabilità ai costruttori

Le risposte migliori qui parlano correttamente della differenza in Kotlin tra sola lettura List(NOTA: è di sola lettura, non "immutabile" ) e MutableList.

In generale, si dovrebbe cercare di utilizzare elenchi di sola lettura, tuttavia, la mutabilità è ancora spesso utile in fase di costruzione , soprattutto quando si tratta di librerie di terze parti con interfacce non funzionali. Per i casi in cui non sono disponibili tecniche di costruzione alternative, come l'uso listOfdiretto o l'applicazione di un costrutto funzionale come foldo reduce, un semplice costrutto "funzione di costruzione" come il seguente produce un elenco di sola lettura da un mutabile temporaneo:

val readonlyList = mutableListOf<...>().apply {
  // manipulate your list here using whatever logic you need
  // the `apply` function sets `this` to the `MutableList`
  add(foo1)
  addAll(foos)
  // etc.
}.toList()

e questo può essere facilmente incapsulato in una funzione di utilità in linea riutilizzabile:

inline fun <T> buildList(block: MutableList<T>.() -> Unit) = 
  mutableListOf<T>().apply(block).toList()

che può essere chiamato così:

val readonlyList = buildList<String> {
  add("foo")
  add("bar")
}

Ora, tutta la mutabilità è isolata in un ambito di blocco utilizzato per la costruzione dell'elenco di sola lettura e il resto del codice utilizza l'elenco di sola lettura che viene generato dal builder.

AGGIORNAMENTO : A partire da Kotlin 1.3.70, la buildListfunzione esatta sopra è disponibile nella libreria standard come funzione sperimentale, insieme ai suoi analoghi buildSete buildMap. Vedi https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .


grazie e ha lavorato bene con la logica aziendale all'interno del metodo apply, ha anche usato un altro List.ForEach {add (pippo)} all'interno del .appy {}
BENN1TH

1

Nel concetto di dati immutabili, forse questo è un modo migliore:

class TempClass {
    val list: List<Int> by lazy {
        listOf<Int>()
    }
    fun doSomething() {
        list += 10
        list -= 10
    }
}

1

A listè immutabledi Default, è possibile utilizzare ArrayListinvece. come questo :

 val orders = arrayListOf<String>()

quindi è possibile add/deleteelementi da questo come di seguito:

orders.add("Item 1")
orders.add("Item 2")

per impostazione predefinita ArrayListè mutablequindi possibile eseguire le operazioni su di esso.

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.