Elixir 歸約和映射算法

2023-12-15 13:50 更新

讓我們看看如何利用遞歸的力量來(lái)計(jì)算一個(gè)列表的數(shù)字之和:

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為參數(shù)調(diào)用了sum_list。我們將逐個(gè)嘗試從句,直到模式匹配成功。這個(gè)案例中,列表[1 ,2, 3]匹配了[head | tail]head對(duì)應(yīng)著1tail對(duì)應(yīng)著[2, 3];accumulator設(shè)置成0。

接著,我們將列表的頭與收集器相加head + accumulator,并將列表的尾作為第一個(gè)參數(shù)再次調(diào)用sum_list。尾會(huì)再次匹配[head | tail]直到列表變空:

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

當(dāng)列表為空時(shí),將匹配最后的從句,返回最終結(jié)果?6?。

將一個(gè)列表歸約成一個(gè)值的過(guò)程叫做歸約算法,它是函數(shù)式編程的中心。

如果我們想將列表中所有值翻倍呢?

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]

這里我們使用遞歸來(lái)遍歷列表,將每個(gè)元素翻倍并返回一個(gè)新的列表。將一個(gè)列表映射到一個(gè)新列表的過(guò)程叫做映射算法。

遞歸和尾調(diào)用是Elixir中的重要部分,且常用于創(chuàng)建環(huán)。然而在實(shí)際使用Elixir時(shí),你很少會(huì)像上面那樣用遞歸來(lái)操作列表。

下一章我們將看到的?Enum?模塊,已經(jīng)提供了許多用于操作列表的便捷方法。實(shí)際中,上述例子可以寫(xiě)成:

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]

或者使用捕獲語(yǔ)法:

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

讓我們進(jìn)一步觀察Enumerable以及它懶惰的相對(duì)物Stream。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)