最近在学习 Elixir 开发,因为它是面向函数的编程语言,像我这种一直做面向对象开发的人来说很多东西很难理解。因此我打算写一系列基础篇的文章,既巩固自己的知识,也希望对其他学习该技术的人有帮助。
我们会以定义,常用的操作符,方法,性能的顺序来进行学习。
Elixir 中的 List 是使用中括号来表示的。Elixir 中的 List 是一个高性能的链表,它意味着 List 内部是[头部, 尾部]
来组成的
iex(27)> [1, 2, true, 3]
iex(28)> [head | tail] = [1, 2, 3]
iex(29)> head
1
iex(30)> tail
[2, 3]
注意,大部分情况下 head 是某一个元素,而 tail 是包含除了第一个元素的其他元素的数组。 因为内部是链表的方式实现的,在头部添加某个元素是很快速的(恒定时间),而添加到尾部所消耗的时间是随着 List 的大小而增加。稍后我们会演示用两种方式追加时候的性能。
# 添加元素
[1, 2] ++ [3] # [1, 2, 3]
# 删除元素
[1, 2, 3, 4] -- [3, 2] # [1, 4]
# 进行比较
[3, 2] === [3, 2] # true
基本上看List 模块和Enum 模块就能了解大部分方法了,下面列出常用的几个。
# 获取头部元素
iex(81)> hd [1,2,3]
1
# 获取尾部数组
iex(82)> tl [1,2,3]
[2, 3]
# 获取列表长度
iex(83)> length [1,2,3]
3
# 遍历元素
iex(84)> Enum.each [1,2,3], fn(x) ->
...(84)> IO.puts x
...(84)> end
1
2
3
# 根据下标进行访问
iex(86)> Enum.fetch([1, 2, 3], 2)
{:ok, 3}
# 删除某个元素
iex(106)> List.delete([1,2,3,4,"a"], "a")
[1, 2, 3, 4] #不保证肯定删除(找到了才删,没找到返回原来的列表)
# 删除指定下标的元素
iex(110)> List.delete_at([1,2,3,4,"a"], 4)
[1, 2, 3, 4] #不保证肯定删除(找到了才删,没找到返回原来的列表)
# 在指定的位置插入新的元素
iex(112)> List.insert_at([1,2,3,4,"a"], 4, 5)
[1, 2, 3, 4, 5, "a"]
# 删除重复元素
iex(88)> Enum.uniq([1, 2, 3, 3, 2, 1])
[1, 2, 3, 2, 1]
# 数组元素进行连接
iex(90)> Enum.join([1, 2, 3])
"123"
iex(91)> Enum.join([1, 2, 3], " = ")
"1 = 2 = 3"
# 随机获取某一个元素
iex(92)> Enum.random [1,2,3,4,5]
1
iex(93)> Enum.random [1,2,3,4,5]
3
# 顺序打乱
iex(94)> Enum.shuffle [1,2,3,4,5]
[4, 5, 3, 2, 1]
# 进行排序
iex(100)> Enum.shuffle([1,2,3,4,5]) |> Enum.sort
[1, 2, 3, 4, 5]
# 从头部获取n个元素
iex(101)> Enum.take([1,2,3,4,5], 3)
[1, 2, 3]
# 随机获取n个元素
iex(102)> Enum.take_random([1,2,3,4,5], 3)
[5, 1, 4]
# 对数组里的数字进行求和
iex(105)> Enum.sum 1..10
55
下面的程序为在头部追加和尾部追加时候的性能对比
defmodule Recursion do
def prepend_elem(list, elem, n) when n <= 1 do
list = elem ++ list
end
def prepend_elem(list, elem, n) do
list = elem ++ list
prepend_elem(list, elem, n - 1)
end
def append_elem(list, elem, n) when n <= 1 do
list = list ++ elem
end
def append_elem(list, elem, n) do
list = list ++ elem
append_elem(list, elem, n - 1)
end
end
IO.puts "start prepend"
prepend_start_time = Time.utc_now |> Time.to_string
list = Recursion.prepend_elem([], [1], 100000)
prepend_end_time = Time.utc_now |> Time.to_string
IO.puts "start at #{prepend_start_time}"
IO.puts "end at #{prepend_end_time}"
IO.puts "------------------------"
IO.puts "start append"
append_start_time = Time.utc_now |> Time.to_string
list = Recursion.append_elem([], [1], 100000)
append_end_time = Time.utc_now |> Time.to_string
IO.puts "start at #{append_start_time}"
IO.puts "end at #{append_end_time}"
start prepend
start at 15:10:24.463439
end at 15:10:24.474485
------------------------
start append
start at 15:10:24.483897
end at 15:10:48.547505
结论: 头部追加 (prepend)10 万次:10 毫秒。 尾部追加 (append)10 万次:24 秒(元素越多越慢),2400 倍