A la lista de Kotlin le faltan "agregar", "eliminar", el mapa "falta", etc.

197

En Java podríamos hacer lo siguiente

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

Pero si lo reescribimos a Kotlin directamente como se muestra a continuación

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

Recibí el error de no encontrar addy removefuncionar de mi lista

Trabajo para enviarlo a ArrayList, pero es extraño tener que hacerlo, mientras que en Java no es necesario. Y eso anula el propósito de tener la clase abstracta Lista

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

¿Hay alguna forma de usar List pero sin necesidad de lanzarlo, como lo que se podría hacer en Java?

Elye
fuente
1
Solo un comentario de por qué no puede hacerlo myList = nully luego más tarde agregar sin llamada !!. Puede superar esto usando la lateinitpalabra clave frente a su propiedad de lateinit var myList: List<Int>esta manera : de esta manera no necesitará inicializar la lista de inmediato, pero le garantiza al compilador que la inicializará antes de usar la lista la primera vez. Es una solución más fluida, pero te responsabiliza como desarrollador.
Darwind

Respuestas:

351

A diferencia de muchos idiomas, Kotlin distingue entre colecciones mutables e inmutables (listas, conjuntos, mapas, etc.). El control preciso sobre exactamente cuándo se pueden editar las colecciones es útil para eliminar errores y para diseñar buenas API.

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

Tendrás que usar una MutableListlista.

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() También debería funcionar.

fulvio
fuente
44
Bonita y bien escrita respuesta. Estoy eligiendo la suya como la respuesta modelo a pesar de tener la mía a continuación :)
Elye
66
No necesita hacer que la lista sea anulable si la inicializa de inmediato. Edité tu respuesta.
Kirill Rakhman
37

Definición de una colección de listas en Kotlin de diferentes maneras:

  • Variable inmutable con lista inmutable (solo lectura):

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


  • Variable inmutable con lista mutable:

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

    o sin valor inicial: lista vacía y sin tipo de variable explícita:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    • puede agregar elementos a la lista:
      • users.add(anohterUser) o
      • users += anotherUser(debajo del capó es users.add(anohterUser))


  • Variable mutable con lista inmutable:

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

    o sin valor inicial: lista vacía y sin tipo de variable explícita:

    var users = emptyList<User>()
    • NOTA: puede agregar * elementos a la lista:
      • users += anotherUser - * crea una nueva ArrayList y la asigna a users


  • Variable mutable con lista mutable:

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

    o sin valor inicial: lista vacía y sin tipo de variable explícita:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    • NOTA: puede agregar elementos a la lista:
      • users.add(anohterUser)
      • pero no usando users += anotherUser

        Error: Kotlin: ambigüedad de operadores de asignación: operador
        público divertido Collection.plus (elemento: String): Lista definida en kotlin.collections
        @InlineOnly operador público en línea divertido MutableCollection.plusAssign (elemento: String): Unidad definida en kotlin.collections


ver también: https://kotlinlang.org/docs/reference/collections.html

Lukas
fuente
9

De acuerdo con todas las respuestas anteriores sobre el uso de MutableList, pero también puede agregar / eliminar de la lista y obtener una nueva lista como se muestra a continuación.

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

O

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
Dinesh Salve
fuente
8

Aparentemente, la Lista predeterminada de Kotlin es inmutable. Para tener una Lista que pueda cambiar, uno debe usar MutableList como se muestra a continuación

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

Actualizado Sin embargo, no se recomienda el uso MutableList a menos de una lista que realmente quiere cambiar. Se refiere a https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 para ver cómo la colección de solo lectura proporciona una mejor codificación.

Elye
fuente
Tienes razón sobre el uso MutableList, sin embargo, inicializarlo nullno funcionará. Solo se permiten llamadas afirmadas seguras o no nulas en un receptor de tipo anulable MutableList<Int>.
fulvio
Funciona de mi parte, y no se encontró ningún error. No necesito inicializarlo a menos que lo necesite cuandodoSomething
Elye
@ Elye Sé que esta es una vieja respuesta y pregunta, pero usar en lateinitlugar de hacer que la lista sea anulable es la forma correcta de abordar este problema. Sin lateinitembargo, no recuerdo si se agregó desde el comienzo de Kotlin, pero esta es definitivamente la solución hoy en día para usarlo :-)
Darwind
5

En Kotlin tienes que usar MutableListo ArrayList.

Veamos cómo funcionan los métodos de MutableListtrabajo:

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

Veamos cómo funcionan los métodos de ArrayListtrabajo:

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
fuente
4

Puedes hacerlo con crear uno nuevo como este.

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

Ahora puedes usar list2, gracias.

Dalvinder Singh
fuente
2

Confinando la mutabilidad a los constructores

Las principales respuestas aquí hablan correctamente de la diferencia en Kotlin entre solo lectura List(NOTA: es de solo lectura, no "inmutable" ) y MutableList.

En general, uno debe esforzarse por usar listas de solo lectura, sin embargo, la mutabilidad sigue siendo útil a menudo en el momento de la construcción , especialmente cuando se trata de bibliotecas de terceros con interfaces no funcionales. Para los casos en los que las técnicas de construcción alternativas no están disponibles, como el uso listOfdirecto o la aplicación de una construcción funcional como foldo reduce, una construcción simple de "función constructora" como la siguiente produce muy bien una lista de solo lectura de una mutable temporal:

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

y esto se puede encapsular muy bien en una función de utilidad en línea reutilizable:

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

que se puede llamar así:

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

Ahora, toda la mutabilidad está aislada en un ámbito de bloque utilizado para la construcción de la lista de solo lectura, y el resto de su código usa la lista de solo lectura que se genera desde el generador.

ACTUALIZACIÓN : A partir de Kotlin 1.3.70, la buildListfunción exacta anterior está disponible en la biblioteca estándar como una función experimental, junto con sus análogos buildSety buildMap. Ver https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .

Raman
fuente
gracias y funcionó bien con la lógica de negocios dentro del método de aplicación, incluso usé otra lista.ForEach {add (foo)} dentro de .appy {}
BENN1TH
1

En concepto de datos inmutables, tal vez esta sea una mejor manera:

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

A listes immutablepor Default, puede usar ArrayListen su lugar. Me gusta esto :

 val orders = arrayListOf<String>()

entonces puedes add/deleteartículos de esto como a continuación:

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

por defecto ArrayListes mutablepara que pueda realizar las operaciones en él.

Trueno
fuente