La liste de Kotlin manque «ajouter», «supprimer», la carte manque «mettre», etc.?

197

En Java, nous pourrions faire ce qui suit

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

Mais si nous le réécrivons directement sur Kotlin comme ci-dessous

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

J'ai eu l'erreur de ne pas trouver addet de removefonctionner dans ma liste

Je travaille autour de la coulée vers ArrayList, mais c'est étrange de devoir la couler, alors qu'en Java la coulée n'est pas requise. Et cela va à l'encontre du but d'avoir la liste de classe abstraite

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

Existe-t-il un moyen d'utiliser List sans avoir besoin de le diffuser, comme ce qui pourrait être fait en Java?

Elye
la source
1
Juste un commentaire pour expliquer pourquoi vous ne pouvez pas le faire myList = null, puis plus tard, appelez sans !!. Vous pouvez surmonter cela en utilisant le lateinitmot - clé devant votre propriété comme ceci: de lateinit var myList: List<Int>cette façon, vous n'aurez pas besoin d'initialiser la liste immédiatement, mais vous garantissez au compilateur que vous l'initialiserez avant d'utiliser la liste la première fois. C'est une solution plus fluide, mais elle vous impose une responsabilité en tant que développeur.
Darwind

Réponses:

351

Contrairement à de nombreuses langues, Kotlin fait la distinction entre les collections mutables et immuables (listes, ensembles, cartes, etc.). Un contrôle précis sur le moment précis où les collections peuvent être modifiées est utile pour éliminer les bogues et pour concevoir de bonnes API.

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

Vous devrez utiliser une MutableListliste.

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() devrait également fonctionner.

fulvio
la source
4
Réponse agréable et bien écrite. Je choisis la vôtre comme réponse du modèle malgré la mienne ci-dessous :)
Elye
6
Vous n'avez pas besoin de rendre la liste nullable si vous l'initialisez immédiatement. J'ai modifié votre réponse.
Kirill Rakhman
37

Définir une collection List dans Kotlin de différentes manières:

  • Variable immuable avec liste immuable (lecture seule):

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


  • Variable immuable avec liste mutable:

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

    ou sans valeur initiale - liste vide et sans type de variable explicite:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    • vous pouvez ajouter des éléments à la liste:
      • users.add(anohterUser) ou
      • users += anotherUser(sous le capot c'est users.add(anohterUser))


  • Variable mutable avec liste immuable:

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

    ou sans valeur initiale - liste vide et sans type de variable explicite:

    var users = emptyList<User>()
    • REMARQUE: vous pouvez ajouter des éléments * à la liste:
      • users += anotherUser - * il crée une nouvelle ArrayList et l'affecte à users


  • Variable mutable avec liste mutable:

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

    ou sans valeur initiale - liste vide et sans type de variable explicite:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    • REMARQUE: vous pouvez ajouter des éléments à la liste:
      • users.add(anohterUser)
      • mais pas en utilisant users += anotherUser

        Erreur: Kotlin: ambiguïté des opérateurs d'affectation: opérateur
        public fun Collection.plus (élément: chaîne): liste définie dans kotlin.collections
        @InlineOnly opérateur public en ligne amusant MutableCollection.plusAssign (élément: chaîne): unité définie dans kotlin.collections


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

Lukas
la source
9

Acceptez toutes les réponses ci-dessus concernant l'utilisation de MutableList, mais vous pouvez également ajouter / supprimer de la liste et obtenir une nouvelle liste comme ci-dessous.

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

Ou

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
baume à dinesh
la source
8

Apparemment, la liste par défaut de Kotlin est immuable. Pour avoir une liste qui pourrait changer, il faut utiliser MutableList comme ci-dessous

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

Mise à jour Néanmoins, il n'est pas recommandé d'utiliser MutableList sauf pour une liste que vous souhaitez vraiment modifier. Fait référence à https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 pour savoir comment la collecte en lecture seule fournit un meilleur codage.

Elye
la source
Vous avez raison d'utiliser MutableList, mais l'initialiser avec nullne fonctionnera pas. Seuls les appels affirmés sûrs ou non nuls sont autorisés sur un récepteur de type nullable MutableList<Int>.
fulvio
Cela fonctionne de mon côté et aucune erreur n'a été trouvée. Je n'ai pas besoin de l'initialiser sauf quand j'en ai besoin quanddoSomething
Elye
@Elye Je sais que c'est une vieille réponse et question, mais utiliser lateinitau lieu de rendre la liste annulable est la bonne façon d'aborder ce problème. Je ne me souviens pas si a lateinitété ajouté depuis le début de Kotlin, mais c'est certainement la solution de nos jours pour l'utiliser :-)
Darwind
5

Dans Kotlin, vous devez utiliser MutableListou ArrayList.

Voyons comment les méthodes de MutableListtravail:

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

Voyons comment les méthodes de ArrayListtravail:

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) 
}
Andy Fedoroff
la source
4

Vous pouvez en créer un comme celui-ci.

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

Vous pouvez maintenant utiliser list2, merci.

Dalvinder Singh
la source
2

Limiter la mutabilité aux constructeurs

Les meilleures réponses ici parlent correctement de la différence dans Kotlin entre lecture seule List(REMARQUE: il est en lecture seule, pas "immuable" ), et MutableList.

En général, on devrait s'efforcer d'utiliser des listes en lecture seule, cependant, la mutabilité est encore souvent utile au moment de la construction , en particulier lorsqu'il s'agit de bibliothèques tierces avec des interfaces non fonctionnelles. Dans les cas où d'autres techniques de construction ne sont pas disponibles, telles que l'utilisation listOfdirecte ou l'application d'une construction fonctionnelle comme foldou reduce, une construction de "fonction de générateur" simple comme celle-ci produit bien une liste en lecture seule à partir d'une liste mutable temporaire:

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

et cela peut être bien encapsulé dans une fonction utilitaire en ligne réutilisable:

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

qui peut être appelé comme ceci:

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

Désormais, toute la mutabilité est isolée dans une étendue de bloc utilisée pour la construction de la liste en lecture seule, et le reste de votre code utilise la liste en lecture seule qui est sortie du générateur.

MISE À JOUR : Depuis Kotlin 1.3.70, la buildListfonction exacte ci-dessus est disponible dans la bibliothèque standard en tant que fonction expérimentale, avec ses analogues buildSetet buildMap. Voir https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .

Raman
la source
merci et a bien fonctionné avec la logique métier au sein de la méthode apply, même utilisé une autre liste (add (foo)} à l'intérieur du .appy {}
BENN1TH
1

Dans le concept de données immuables, c'est peut-être une meilleure façon:

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

A listest immutablepar Default, vous pouvez utiliser à la ArrayListplace. comme ça :

 val orders = arrayListOf<String>()

alors vous pouvez les add/deletearticles de ce genre comme ci-dessous:

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

par défaut ArrayListest pour mutableque vous puissiez effectuer les opérations là - dessus.

Tonnerre
la source