Elixir 归约和映射算法

2023-12-15 13:50 更新

让我们看看如何利用递归的力量来计算一个列表的数字之和:

defmodule Math do
  def sum_list([head | tail], accumulator) do
    sum_list(tail, head + accumulator)
  end

  def sum_list([], accumulator) do
    accumulator
  end
end

IO.puts Math.sum_list([1, 2, 3], 0) #=> 6

我们以列表[1, 2, 3]和初始值0为参数调用了sum_list。我们将逐个尝试从句,直到模式匹配成功。这个案例中,列表[1 ,2, 3]匹配了[head | tail]head对应着1tail对应着[2, 3]accumulator设置成0

接着,我们将列表的头与收集器相加head + accumulator,并将列表的尾作为第一个参数再次调用sum_list。尾会再次匹配[head | tail]直到列表变空:

sum_list [1, 2, 3], 0
sum_list [2, 3], 1
sum_list [3], 3
sum_list [], 6

当列表为空时,将匹配最后的从句,返回最终结果​6​。

将一个列表归约成一个值的过程叫做归约算法,它是函数式编程的中心。

如果我们想将列表中所有值翻倍呢?

defmodule Math do
  def double_each([head | tail]) do
    [head * 2 | double_each(tail)]
  end

  def double_each([]) do
    []
  end
end
iex math.exs
iex> Math.double_each([1, 2, 3]) #=> [2, 4, 6]

这里我们使用递归来遍历列表,将每个元素翻倍并返回一个新的列表。将一个列表映射到一个新列表的过程叫做映射算法。

递归和尾调用是Elixir中的重要部分,且常用于创建环。然而在实际使用Elixir时,你很少会像上面那样用递归来操作列表。

下一章我们将看到的​Enum​模块,已经提供了许多用于操作列表的便捷方法。实际中,上述例子可以写成:

iex> Enum.reduce([1, 2, 3], 0, fn(x, acc) -> x + acc end)
6
iex> Enum.map([1, 2, 3], fn(x) -> x * 2 end)
[2, 4, 6]

或者使用捕获语法:

iex> Enum.reduce([1, 2, 3], 0, &+/2)
6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]

让我们进一步观察Enumerable以及它懒惰的相对物Stream


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号