Una col·lecció és un conjunt de dades.
Introducció
A Llista (i Map) vas veure una de les col·leccions més utilitzades.
Les col·leccions tenen funcions genèriques semblants a les que vam veure a l’activitat Function type.
Iterar
forEach
data class Person(val name: String, val age: Int)
val list = listOf(Person("Joan", 25), Person("Laura", 30), Person("Mireia", 35)))
list.forEach { println(it.name) }
Transformar
La biblioteca estàndard de Kotlin proporciona un conjunt de funcions d’extensió per a transformacions de col·leccions.
Aquestes funcions construeixen col·leccions noves a partir d’altres existents segons les regles de transformació proporcionades.
map
La transformació de mapatge crea una col·lecció a partir dels resultats d’aplicar una funció als elements d’una altra col·lecció.
La funció bàsica de mapatge és map()
: aplica la funció lambda donada a cada element i retorna la llista dels resultats.
L’ordre dels resultats és el mateix que l’ordre original dels elements.
assert( listOf(1, 2, 3).mapNotNull { if (it == 2) null else it * 3 } == listOf(3, 6))
Si la transformació produeix null
en determinats elements, pots eliminar els null
de la col·lecció resultant cridant la funció mapNotNull()
en comptes de map()
:
assert( listOf(1, 2, 3).mapNotNull { if (it == 2) null else it * 3 } == listOf(3, 6))
Map
Quan transformes un Map, tens dues opcions: transformar les claus mantenint els valors sense canvis i a l’inrevés.
Per exemple, si tens un registre d’estudiants amb la seva nota:
val students = mapOf("David" to 10, "Mireia" to 8, "Laura" to 3, "Laia" to 5)
Amb la funció mapValues()
pots apujar la nota de tots els estudiants que han tret una nota igual o superior a 5:
assert( students.mapValues { (_, grade) -> if (grade in 5..<10) grade + 1 else grade } == mapOf("David" to 10, "Mireia" to 9, "Laura" to 3, "Laia" to 6))
I amb la funció mapKeys()
pots posar en minúscula els noms dels estudiants:
assert( students.mapKeys { (name, _) -> name.lowercase() } == mapOf("david" to 10, "mireia" to 8, "laura" to 3, "laia" to 5))
Si vols pots fer les dues coses al mateix temps, una darrere de l’altre:
assert( students. mapKeys { (name, _) -> name.lowercase() }. mapValues { (_, grade) -> if (grade in 5..<10) grade + 1 else grade } == mapOf("david" to 10, "mireia" to 9, "laura" to 3, "laia" to 6))
Altres
Més informació a Transformations
Filtrar
El filtratge és una de les tasques més populars en el processament de col·leccions.
Les condicions de filtratge es defineixen mitjançant predicats: funcions lambda que prenen un element de la col·lecció i retornen un valor booleà: true
vol dir que l’element compleix el predicat, false
vol dir el contrari.
Filtrar per predicat
La funció bàsica de filtratge és filter()
.
Quan es crida amb un predicat, filter()
retorna els elements de la col·lecció que el compleixen
A continuació tens una llista de mascotes:
enum class Type { DOG, CAT, TURTLE }data class Pet(val name: String, val type: Type, val age: Int)
fun main() {
val pets = listOf( Pet("Snoopy", Type.DOG, 3), Pet(name = "Garfield", Type.CAT, age = 12), Pet("Milú", Type.DOG, 10), Pet(name = "Felix", type = Type.CAT, age = 10), Pet("Harrite", Type.TURTLE, 90) )}
A continuació filtrem la llista amb només aquelles mascotes que són gossos:
assert( pets.filter { it.type == Type.DOG } == listOf( Pet("Snoopy", Type.DOG, 3), Pet("Milú", Type.DOG, 10) ))
Filtra la llista amb només els gats que tenen més de 10 anys.
assert( pets.filter { it.age > 10 && it.type == Type.CAT } == listOf( Pet(name = "Garfield", Type.CAT, age = 12) ))
Filtra la llista pets
amb només gats i mapeja els resultats a una llista de noms de mascotes.
assert( pets.filter { it.type == Type.CAT }.map { it.name } == listOf("Garfield", "Felix"))
Per filtrar col·leccions per condicions negatives, utilitza filterNot()
.
Retorna una llista d’elements per als quals el predicat dona com a resultat false
.
Per exemple, el nom de totes les màscotes que no són tortugues:
assert( pets.filterNot { it.type == Type.TURTLE }.map { it.name } == listOf("Snoopy", "Garfield", "Milú", "Felix"))
filterNotNull()
retorna tots els elements no nuls.
Si es crida sobre una List<T?>
, filterNotNull()
retorna una List<T: Any>
, permetent-te tractar els elements com a no nuls.
assert( listOf(null, "Joana", "Maria", null, "Pere").filterNotNull() == listOf("Joana", "Maria", "Pere"))
Test predicates
filterNotNull() returns all non-nullable elements.
Being called on a List<T?>
, filterNotNull()
returns a List<T: Any>
, thus allowing you to treat the elements as non-nullable objects.
val numbers = listOf(null, "one", "two", null)
numbers.filterNotNull().forEach {
println(it.length) // length is unavailable for nullable Strings
}
Partition
Another filtering function – partition() – filters a collection by a predicate and keeps the elements that don’t match it in a separate list. So, you have a Pair of Lists as a return value: the first list containing elements that match the predicate and the second one containing everything else from the original collection.
val numbers = listOf("one", "two", "three", "four")
val (match, rest) = numbers.partition { it.length > 3 }
println(match)
println(rest)
Test predicates
Finally, there are functions that simply test a predicate against collection elements:
-
any() returns true if at least one element matches the given predicate.
-
none() returns true if none of the elements match the given predicate.
-
all() returns true if all elements match the given predicate. Note that all() returns true when called with any valid predicate on an empty collection. Such behavior is known in logic as vacuous truth.
val numbers = listOf("one", "two", "three", "four")
println(numbers.any { it.endsWith("e") })
println(numbers.none { it.endsWith("a") })
println(numbers.all { it.endsWith("e") })
println(emptyList<Int>().all { it > 5 }) // vacuous truth
any() and none() can also be used without a predicate: in this case they just check the collection emptiness. any() returns true if there are elements and false if there aren’t; none() does the opposite.
val numbers = listOf("one", "two", "three", "four")
val empty = emptyList<String>()
println(numbers.any())
println(empty.any())
println(numbers.none())
println(empty.none())
ordering
aggregate
take
TODO
Continuem: