5.3.7 映射操作符

map(transform: (T) -> R): List<R>

将集合中的元素通过转换函数transform映射后的结果,存到一个集合中返回。

  1. >>> val list = listOf(1,2,3,4,5,6,7)
  2. >>> list.map({it})
  3. [1, 2, 3, 4, 5, 6, 7]
  4. >>> list.map({it*it})
  5. [1, 4, 9, 16, 25, 36, 49]
  6. >>> list.map({it+10})
  7. [11, 12, 13, 14, 15, 16, 17]

这个函数内部调用的是

  1. public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
  2. return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
  3. }

这里的mapTo函数定义如下:

  1. public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
  2. for (item in this)
  3. destination.add(transform(item))
  4. return destination
  5. }

我们可以看出,这个map实现的原理是循环遍历原集合中的元素,并把通过transform映射后的结果放到一个新的destination集合中,并返回destination。#### mapIndexed(transform: (kotlin.Int, T) -> R)

转换函数transform中带有下标参数。也就是说我们可以同时使用下标和元素的值来进行转换。 其中,第一个参数是Int类型的下标。

代码示例:

  1. >>> val list = listOf(1,2,3,4,5,6,7)
  2. >>> list.mapIndexed({index,it -> index*it})
  3. [0, 2, 6, 12, 20, 30, 42]
  4. ```#### `mapNotNull(transform: (T) -> R?)`
  5. 遍历集合每个元素,得到通过函数算子transform映射之后的值,剔除掉这些值中的null,返回一个无null元素的集合。
  6. 代码示例:
  7. ```kotlin
  8. >>> val list = listOf("a","b",null,"x",null,"z")
  9. >>> list.mapNotNull({it})
  10. [a, b, x, z]

这个函数内部实现是调用的mapNotNullTo函数:

  1. public inline fun <T, R : Any, C : MutableCollection<in R>> Iterable<T>.mapNotNullTo(destination: C, transform: (T) -> R?): C {
  2. forEach { element -> transform(element)?.let { destination.add(it) } }
  3. return destination
  4. }
  5. ```#### `flatMap(transform: (T) -> Iterable<R>): List<R>`
  6. 在原始集合的每个元素上调用`transform`转换函数,得到的映射结果组成的单个列表。为了更简单的理解这个函数,我们跟`map(transform: (T) -> R): List<R>`对比下。
  7. 首先看函数的各自的实现:
  8. map:
  9. ```kotlin
  10. public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
  11. return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
  12. }
  13. public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
  14. for (item in this)
  15. destination.add(transform(item))
  16. return destination
  17. }

flatMap:

  1. public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
  2. return flatMapTo(ArrayList<R>(), transform)
  3. }
  4. public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
  5. for (element in this) {
  6. val list = transform(element)
  7. destination.addAll(list)
  8. }
  9. return destination
  10. }

我们可以看出,这两个函数主要区别在transform函数返回上。

代码示例

  1. >>> val list = listOf("a","b","c")
  2. >>> list.map({it->listOf(it+1,it+2,it+3)})
  3. [[a1, a2, a3], [b1, b2, b3], [c1, c2, c3]]
  4. >>> list.flatMap({it->listOf(it+1,it+2,it+3)})
  5. [a1, a2, a3, b1, b2, b3, c1, c2, c3]

从代码运行结果我们可以看出,使用 map 是把list中的每一个元素都映射成一个List-n,然后以这些List-n为元素,组成一个大的嵌套的List返回。而使用flatMap则是把list中的第一个元素映射成一个List1,然后把第二个元素映射成的List2跟List1合并:List1.addAll(List2),以此类推。最终返回一个“扁平的”(flat)List。

其实,这个flatMap的过程是 map + flatten两个操作的组合。这个flatten函数定义如下:

  1. public fun <T> Iterable<Iterable<T>>.flatten(): List<T> {
  2. val result = ArrayList<T>()
  3. for (element in this) {
  4. result.addAll(element)
  5. }
  6. return result
  7. }

代码示例:

  1. >>> val list = listOf("a","b","c")
  2. >>> list.map({it->listOf(it+1,it+2,it+3)})
  3. [[a1, a2, a3], [b1, b2, b3], [c1, c2, c3]]
  4. >>> list.map({it->listOf(it+1,it+2,it+3)}).flatten()
  5. [a1, a2, a3, b1, b2, b3, c1, c2, c3]