Erlang笔记 -- 常用数据结构

元组tuple

元组,用于保存固定数量的元素。创建元组的方法就是用大括号{}把想要表达的值括起来,并用逗号分隔他们。例如,表示某人的年龄:{Jack, 18}
Erlang没有类型声明,创建一个坐标点,只需:

P = {
   10, 15}.

这样就创建了一个元祖并绑定在变量P上。
由于元组里的字段没有名字,为了记住该元组的用途,通常会写成以下方式:{point, 10, 15},这样提高使程序的可理解性。
元组是可以嵌套的,例如:

1> Person = {
   person, {
   name, Jack}, {
   age, 18}}.
{
   person, {
   name, Jack}, {
   age, 18}}
1. 创建元组

元组会在声明他们的时候自动创建,不再使用时被销毁。如果在构建新的元组时用到变量,那么新的元组会共享该变量所引用的数据结构的值。例如,

2> F = {
   firstname, jack}.
{
   firstname, jack}
3> L = {
   lastname, chan}.
{
   lastname, chan}
4> p = {
   person, F, L}.
{
   person, {
   firstname, jack}, {
   lastname, chan}}
2. 提取元组的值

通过使用模式匹配操作符=从元组中提取一些值。

1> Point = {
   point,10,15}.
{
   point,10,15}
2> {
   point,X,Y} = Point.
{
   point,10,15}
3> X.
10
4> Y.
15

注意:等号两侧的元组必须要有相同数量的元素,而且两侧的对应元素必须绑定为相同的值。如:

5> Point1 = {
   point,5,5}.
{
   point,5,5}
6> {
   point,C,C} = Point1.
{
   point,5,5}
7> C.
5

如果有一个复杂的元组,就可以编写一个与该元组形状(结构)相同的模式,并在待提取值的位置加入未绑定的变量来提取该值。

Eshell V8.3  (abort with ^G)
1> Person = {
   person,{
   name,jack,chan},{
   age,18}}.
{
   person,{
   name,jack,chan},{
   age,18}}
2> {
   _, {
   _, Who, _}, _} = Person.
{
   person,{
   name,jack,chan},{
   age,18}}
3> Who.
jack

其中,"_“被称为匿名变量。与正规变量不同,同一模式里的多个”_"不必绑定相同的值。

列表list

列表,被用来存放任意数量的事物。创建列表的方法是用中括号[]把列表元素括起来,并用逗号分隔开。
列表的第一个元素称为列表头head,其余部分称为列表尾tail。例如:列表[1, 2, 3, 4, 5]的列表头为整数1,[2, 3, 4, 5]为列表尾。

1. 定义列表

如果T是一个列表,那么[H | T]也是一个列表,他的头是H,尾是T。竖线 | 把列表的头与尾分隔开。[]是一个空列表。
无论何时,只要用[... | T]表示一个列表,就应该确保T是列表。此时称为格式正确的列表,否则称为不正确的列表。
可以给T的开头添加不止一个元素,写法是[E1,E2,...,EN | T]

1> T = [{
   apple, 10}, {
   pear, 5}].
[{
   apple, 10}, {
   pear, 5}]
2> T1 = [{
   orange, 15} | T].
[{
   orange, 15}, {
   apple, 10}, {
   pear, 5}]
2. 提取列表元素

通过模式匹配操作来提取某个列表里的元素。如果有一个列表L,那么表达式[X | Y] = L会提取列表头作为X,列表尾作为Y

3> [B1 | B2] = T1.
[{
   orange, 15}, {
   apple, 10}, {
   pear, 5}]
4> B1.
{
   orange, 15}
5> B2.
[{
   apple, 10}, {
   pear, 5}]
3. 列表处理注意点
Eshell V8.3  (abort with ^G)
1> A = [[1,2],[2,3],[3,4]].
[[1,2],[2,3],[3,4]]
2> [B,C|T] = A.
[[1,2],[2,3],[3,4]]
3> B.
[1,2]
4> C.
[2,3]
5> T.
[[3,4]]
6> D = [1,2,3].
[1,2,3]
7> E = [3,4,5,6].
[3,4,5,6]
8> F = [D|E].
[[1,2,3],3,4,5,6]
9> G = D ++ E.
[1,2,3,3,4,5,6]
4. 列表推导

[F(X) || X <- L]标记表示“由F(X)组成的列表(X从列表L中提取)”。[2 *X || X <- L]表示“由2 * X组成的列表”。
以下实现将列表中每一项的数字加倍:

1> Buy = [{
   apples,1},{
   pears,2},{
   newspaper,1}].
[{
   apples,1},{
   pears,2},{
   newspaper,1}]
2> [{
   Name,2*Num} || {
   Name,Num} <- Buy].
[{
   apples,2},{
   pears,4},{
   newspaper,2}]

注意,|| 右侧的元组{Name, Number}是一个模式,用于匹配Buy中的各个元素。左侧的元组{Name, 2*Number}是一个构造器

列表推导最常规的形式是下面这种表达式:

[X || Qualifier1, Qualifier2, ...]

X是任意一条表达式,后面的限定符(Qualifier)可以是生成器、位串生成器或过滤器。

  • 生成器(generator)的写法是Pattern <- ListExpr,其中的ListExp必须是一个能够得出列表的表达式。
  • 位串(bitstring)生成器的写法是BitStringPattern <= BitStringExpr,其中的BitStringExpr必须是一个能够得出位串的表达式。
  • 过滤器(filter)既可以是判断函数(即返回truefalse的函数),也可以是布尔表达式。
5. 列表常用函数
  • lists:keyfind(Key, N, TupleList) -> Tuple | false
    在元组列表TupleList中搜索第n个元素与Key相等的元组。如果找到这样的元组,则返回元组,否则返回false

  • lists:keystore(Key, N, TupleList1, NewTuple) -> TupleList2
    返回TupleList1的副本,其中第n个元素等于Key的元组T的第一个出现位置将被替换为NewTuple,如果没有这样的元组T,则返回TupleList1的副本,并将[NewTuple]附加到末尾。

  • lists:keysort(N, TupleList1) -> TupleList2
    返回一个包含列表TupleList1的已排序元素的列表。排序是在元组的第n个元素上执行的。

  • lists:sort(Fun, List1) -> List2
    根据排序函数Fun,返回一个包含List1排序元素的列表。

  • lists:usort(List1) -> List2
    返回一个包含List1的已排序元素的列表,并删除重复项。

  • lists:keymember(Key, N, TupleList) -> boolean()
    如果TupleList中有一个元组,其第n个元素与Key相等,则返回true,否则返回false

  • lists:member(Elem, List) -> boolean()
    如果Elem在列表List中,则返回true,否则返回false

  • lists:sublist(List1, Len) -> List2
    返回List1的子列表,从位置1开始,包含Len个元素。当Len超过列表的长度时,将返回整个列表。

  • lists:sublist(List1, Start, Len) -> List2
    返回List1的子列表,从位置Start开始,包含Len个元素。当Start+Len超过列表的长度时,将返回整个列表。

  • lists:foldl(Fun, Acc0, List) -> Acc1
    对列表的连续元素Elem调用Fun(Elem,AccIn),从AccIn==Acc0开始。Fun/2必须返回一个新的累加器,它被传递给下一个调用。函数返回累加器的最终值。如果列表为空,则返回Acc0

  • lists:foldr(Fun, Acc0, List) -> Acc1
    同foldl/3,但遍历元素顺序为从右到左。如下:

> P = fun(A, AccIn) -> io:format("~p ", [A]), AccIn end.
#Fun<erl_eval.12.2225172>
> lists:foldl(P, void, [1,2,3]).
1 2 3 void
> lists:foldr(P, void, [1,2,3]).
3 2 1 void
  • lists:any(Pred, List) -> boolean()
    Pred = fun((Elem :: T) -> boolean())
    List = [T]
    T = term()
    如果列表中至少一个元素Elem使得Pred(Elem)返回true,则返回true

  • lists:all(Pred, List) -> boolean()
    如果列表中所有元素Elem都使得Pred(Elem)返回true,则返回true

  • lists:nthtail(N, list) -> Tail
    返回从N+1开始一直到列表的结尾的子列表。

  • lists:nth(N, List) -> Elem
    返回列表的第n个元素。

  • erlang:hd(List)
    返回列表的头,即第一个元素。

  • lists:last(List) -> Elem
    返回列表中的最后一个元素。

  • lists:flatmap(Fun, List1) -> List2
    //Fun = fun((A) -> [B])
    //List1 = [A]
    //List2 = [B]
    //A = B = term()
    Takes a function from As to lists of Bs, and a list of As (List1) and produces a list of Bs by applying the function to every element in List1 and appending the resulting lists.
    That is, flatmap behaves as if it had been defined as follows:

flatmap(Fun, List1) -> append(map(Fun, List1)).

Example:

> lists:flatmap(fun(X)->[X,X] end, [a,b,c]).
[a,a,b,b,c,c]

记录record

记录是元组的另一种形式,通过使用记录,可以给元组里的各个元素关联一个名称。
用记录声明命名元组里的元素,语法如下:

-record(Name, {
   
	%%以下两个键带有默认值
	key1 = Default1,
	key2 = Default2,
	...
	%%下一行就相当于Key3 = Undefined
	Key3,
	...     
}).

-record不是一个shell命令,在shell里要使用rr。记录声明只能在Erlang源代码模块里使用,不能用于shell。
Name是记录名。Key1Key2这些是记录中各个字段的名称,他们必须是原子。记录里的每个字段都可以带一个默认值,如果创建记录时没有指定某个字段值,就会使用默认值。
记录的定义既可以保存在Erlang源代码文件里,也可以由扩展名为.hrl的文件保存,然后包含在Erlang源代码文件里。
文件包含是唯一能确保多个Erlang模块共享相同记录定义的方式。

%% records.hrl
-record(todo, {
   status=reminder, who=jack, text}).

记录一旦定义,就可以创建该记录的实例了。

要在shell中创建实例,必须先把记录的定义读入shell。

1> rr("record.hrl").
[todo]

rr是read records的缩写,即读取记录

1. 创建记录
2> #todo{
   }.
#todo{
   status = reminder,who = jack,text = undefined}
3> X1 = #todo{
   status = urgent, text = "So urgent"}.
#todo{
   status = urgent,who = jack,text = "So urgent"}
4> X2 = X1#todo{
   status = done}.
#
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值