Collection Pipelines

map, filter, reduce and the Collections Pipeline

filter, map and sortedBy never modify their receiver; each returns a new read-only list, so you chain them as you chain JavaScript array methods, with a trailing lambda (Lambdas) whose it is the element.

The catalog through filter, sortedBy, map, groupBy, fold and reduce (Pipeline.kt)Kotlin
fun main() {
  val cheapInStock = books
    .filter { it.inStock && it.price < 20.0 }
    .sortedBy { it.price }
    .map { "${it.title} $${it.price}" }
  println(cheapInStock)
  val bySize = books.groupBy { if (it.pages > 300) "long" else "short" }
  println(bySize.mapValues { (_, list) -> list.map { it.id } })
  val stockValue = books.filter { it.inStock }.fold(0.0) { acc, b -> acc + b.price }
  val mostPages = books.map { it.pages }.reduce { a, b -> maxOf(a, b) }
  println("stock value %.2f, longest %d pages".format(stockValue, mostPages))
  println(runCatching { emptyList<Int>().reduce { a, b -> a + b } }.exceptionOrNull())
}
Output
[The Quiet Harbor $14.99, The Clockmaker's Paradox $16.2, Small Steps to Big Summits $18.75]
{long=[1, 2, 5], short=[3, 4, 6]}
stock value 110.74, longest 428 pages
java.lang.UnsupportedOperationException: Empty collection can't be reduced.

groupBy returns a Map<K, List<T>> that keeps keys in first-seen order; associate { it.id to it.title } builds a map from Pairs. sortedBy is stable: equal prices keep their order. Kotlin splits JavaScript's reduce in two: fold takes an initial value and may return any type, while reduce starts from the first element and throws on an empty collection, as the last line shows. Prefer fold, or sumOf { it.price }, whenever the input can be empty.