Elixir 歸約和映射算法

2023-12-15 13:50 更新

讓我們看看如何利用遞歸的力量來計算一個列表的數(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。我們將逐個嘗試從句,直到模式匹配成功。這個案例中,列表[1 ,2, 3]匹配了[head | tail],head對應著1tail對應著[2, 3]accumulator設(shè)置成0。

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

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

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

將一個列表歸約成一個值的過程叫做歸約算法,它是函數(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]

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

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

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

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。


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號