Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

折叠列表

fold() 将列表中的所有元素依次组合在一起,生成单个结果。

一个常见的练习是使用 fold() 实现诸如 sum()reverse() 之类的操作。在这里,fold() 对序列求和:

// FoldingLists/SumViaFold.kt
import atomictest.eq

fun main() {
  val list = listOf(1, 10, 100, 1000)
  list.fold(0) { sum, n ->
    sum + n
  } eq 1111
}

fold() 接受初始值(在这种情况下是参数 0),并逐个将操作(在这里表示为 lambda)应用于将当前累积值与每个元素组合在一起。fold() 首先将 0(初始值)和 1 相加,得到 1。这成为了 sum,然后将其与 10 相加,得到 11,这成为了新的 sum。该操作对两个其他元素(1001000)重复执行。这产生了 1111111。当列表中没有其他内容时,fold() 将停止,并返回最终的 sum,即 1111。当然,fold() 实际上并不知道它正在执行“求和”操作,我们选择了标识符名称,以使理解更容易。

为了阐明 fold() 中的步骤,以下是使用普通的 for 循环编写的 SumViaFold.kt

// FoldingLists/FoldVsForLoop.kt
import atomictest.eq

fun main() {
  val list = listOf(1, 10, 100, 1000)
  var accumulator = 0
  val operation =
    { sum: Int, i: Int -> sum + i }
  for (i in list) {
    accumulator = operation(accumulator, i)
  }
  accumulator eq 1111
}

fold() 通过逐个将 operation 应用于将当前元素与累积值组合在一起来累积值。

尽管 fold() 是一个重要的概念,也是在纯函数式语言中累积值的唯一方法,但在 Kotlin 中有时仍然会使用普通的 for 循环。

foldRight() 从右到左处理元素,与从左到右处理元素的 fold() 相反。以下示例演示了这种差异:

// FoldingLists/FoldRight.kt
import atomictest.eq

fun main() {
  val list = listOf('a', 'b', 'c', 'd')
  list.fold("*") { acc, elem ->
    "($acc) + $elem"
  } eq "((((*) + a) + b) + c) + d"
  list.foldRight("*") { elem, acc ->
    "$elem + ($acc)"
  } eq "a + (b + (c + (d + (*))))"
}

fold() 首先将操作应用于 a,如 (*) + a 所示,而 foldRight() 首先处理右侧的元素 d,然后最后处理 a

fold()foldRight() 的第一个参数是显式的累加器值。有时,第一个元素可以充当初始值。reduce()reduceRight() 的行为类似于 fold()foldRight(),但分别使用第一个和最后一个元素作为初始值:

// FoldingLists/ReduceAndReduceRight.kt
import atomictest.eq

fun main() {
  val chars = "A B C D E F G H I".split(" ")
  chars.fold("X") { a, e -> "$a $e"} eq
    "X A B C D E F G H I"
  chars.foldRight("X") { a, e -> "$a $e" } eq
    "A B C D E F G H I X"
  chars.reduce { a, e -> "$a $e" } eq
    "A B C D E F G H I"
  chars.reduceRight { a, e -> "$a $e" } eq
    "A B C D E F G H I"
}

runningFold()runningReduce() 生成一个包含过程中所有中间步骤的 ListList 中的最终值是 fold()reduce() 的结果:

// FoldingLists/RunningFold.kt
import atomictest.eq

fun main() {
  val list = listOf(11, 13, 17, 19)
  list.fold(7) { sum, n ->
    sum + n
  } eq 67
  list.runningFold(7) { sum, n ->
    sum + n
  } eq "[7, 18, 31, 48, 67]"
  list.reduce { sum, n ->
    sum + n
  } eq 60
  list.runningReduce { sum, n ->
    sum + n
  } eq "[11, 24, 41, 60]"
}

runningFold() 首先存储初始值(7),然后存储每个中间结果。runningReduce() 会跟踪每个 sum 值。

练习和解答可以在 www.AtomicKotlin.com 找到。