Elixir-列表与递归

递归 才是处理列表的最佳工具。

头部和尾部

列表可以通过管道运算符 | 来分隔头部和尾部。

1
2
3
4
5
6
iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
  • 空列表长度为 0
  • 列表长度等于列表尾部长度 + 1

递归计算列表长度

1
2
3
4
defmodule Demo do
def len([]), do: 0
def len([_head | tail]), do: len(tail) + 1
end
1
2
iex> Demo.len [1,2,3,4,5]
5

head变量没有被用到,可以使用_开头的变量名来消除编译警告(_head)。

## 创建映射函数

1
2
3
4
defmodule Demo do
def map([], _func), do: []
def map([head | tail], func), do: [func.(head) | map(tail, func)]
end

_func 没有被使用,所以_开头

1
2
3
4
iex> Demo.len [1,3,4,5], &(&1*10)
[10, 30, 40, 50]
iex> Demo.len [1,3,4,5], &(&1/10)
[0.1, 0.3, 0.4, 0.5]

方便对列表进行操作。

递归时跟踪值

列表求和:

1
2
3
4
5
6
7
8
defmodule Demo do
#公开函数,内部调用_sum
def sum(list), do: _sum(list, 0)

#私有函数,递归求和
defp _sum([], total), do: total
defp _sum([head | tail], total), do: _sum(tail, head + total)
end
1
2
3
4
iex> Demo.sum [1,2,3,4,5]
15
iex> Demo.sum [10,20,30,40,50]
150
  • 第一 defp 来定义私有函数
  • 第二给辅助函数取和公开函数一样的名称,但以 _ 开头。

更复杂的列表

不是所有的列表问题都可以简单的一次处理一个元素来解决,幸好我们有连接运算符 |,左边允许有多个值。

1
2
3
4
5
defmodule Demo do
def swap([]), do: []
def swap([a,b | tail]), do: [b,a | swap(tail)]
def swap(_), do: raise "error, odd number of elements is not allowed"
end
1
2
3
4
5
6
iex(37)> Demo.swap [1,2,3,4,5,6]
[2, 1, 4, 3, 6, 5]
iex(38)> Demo.swap [1,2,3,4,5]
** (RuntimeError) error, odd number of elements is not allowed
e:/Elixir_workspace/hello.exs:4: Demo.swap/1
e:/Elixir_workspace/hello.exs:3: Demo.swap/1

raise 抛出一个异常,相当于 java 的 throw 对不关心的域使用 _ 占位符

看官赏点饭钱可好~