erlang有两种复合结构,tuple和list,两者的区别是tuple子元素的个数是固定不变的,声明后就不能改变了;而list是可变的,可以通过[H|T]来取出或插入新元素。上篇文章讲了tuple相关的内容,本篇就讲erlang list方面的知识,主要说一些基本操作和常用的list函数,再讲一些可以优化的点。
list基本操作
1> A = [1, 2, 3, "abc"].
[1,2,3,"abc"]
2> length(A).
4
3> is_list(A).
true
4> list_to_binary(A).
<<1,2,3,97,98,99>>
5> list_to_bitstring(A).
<<1,2,3,97,98,99>>
6> [A1|A2] = A.
[1,2,3,"abc"]
7> A1.
1
8> A2.
[2,3,"abc"]
9> hd(A).
1
10> tl(A).
[2,3,"abc"]
11> B = [0|A].
[0,1,2,3,"abc"]
list函数说明
常用的lists函数
这里介绍一些常用的lists函数,其他看erlang lists文档
lists:foreach(Fun, List) -> ok
1> lists:foreach(fun(X) -> io:format("~p~n", [X]) end, [1,2,3]).
1
2
3
ok
例子中,通过遍历列表[1,2,3],把取出的元素给X,直到遍历结束,最后返回ok
lists:foldl(Fun, Acc0, List) -> Acc1
2> lists:foldl(fun(X, Sum) -> X + Sum end, 0, [1,2,3,4,5]).
15
例子中,0指定了Sum的初值,通过遍历列表[1,2,3,4,5],把取出的元素给X,再计算X+Sum,结果带入下次遍历传给Sum,直到最后一次遍历将X+Sum的结果作为返回值
下面是lists:foldl/3 的实现,实际上是一个尾递归函数
foldl(F, Accu, [Hd|Tail]) ->
foldl(F, F(Hd, Accu), Tail);
foldl(F, Accu, []) when is_function(F, 2) ->
Accu.
lists:reverse(List1) -> List2
3> lists:reverse([1,2,3,4,5]).
[5,4,3,2,1]
list反转(这是个bif函数,效率较高)
lists:flatten(DeepList) -> List
4> lists:flatten([1,[2,3],[4,[5]],6]).
[1,2,3,4,5,6]
lists扁平化,将有深度结构的list转成一个简单的list。这个函数有性能开销,见文章后面说明。
lists:member(Elem, List) -> boolean()
5> lists:member(3,[1,2,3]).
true
检查元素是否存在list中(这是个bif函数,效率较高)
lists:sort(List1) -> List2
6> lists:sort([2,3,1]).
[1,2,3]
lists元素排序,排序从小到大,如果想自定义排序规则,可以使用lists:sort/2
lists:sort(Fun, List1) -> List2
7> lists:sort(fun(A,B)-> A>=B end,[2,3,1]).
[3,2,1]
处理TupleList的lists函数
TupleList是元素是tuple的list,erlang提供了一些接口专门处理这类数据。
lists:keymember(Key, N, TupleList) -> boolean()
8> lists:keymember(b,1,[{a,1,1},{b,1,1},{c,1,1}]).
true
检查list中是否有第N位置为Key的tuple(这是个
bif函数,效率较高)
lists:keyfind(Key, N, TupleList) -> Tuple | false
9> lists:keyfind(b,1,[{a,1,1},{b,1,1},{c,1,1}]).
{b,1,1}
返回list中第N位置为Key的tuple,找不到返回false
注:
1. 找到第一个匹配的tuple就返回,找不到返回false
2. 这个接口可以替代lists:keysearch(Key, N, TupleList) 使用
3.这是个bif函数,效率较高
lists:keysearch(Key, N, TupleList)的官方文档中有这么一句:
This function is retained for backward compatibility. The function lists:keyfind/3 (introduced in R13A) is in most cases more convenient.
意思就是说lists:keysearch/3只是为了保持向后兼容,使用lists:keyfind/3会更方便
lists:keytake(Key, N, TupleList1) -> {value, Tuple, TupleList2} | false
10> lists:keytake(b,1,[{a,1,1},{b,1,1},{c,1,1}]).
{value,{b,1,1},[{a,1,1},{c,1,1}]}
返回list中第N位置为Key的tuple,并返回找到的tuple和剩下的TupleList,找不到返回false
注:找到第一个匹配的tuple就返回
lists:keyreplace(Key, N, TupleList1, NewTuple) -> TupleList2
11> lists:keyreplace(b,1,[{a,1,1},{b,1,1},{c,1,1}], {b,2,2}).
[{a,1,1},{b,2,2},{c,1,1}]
替换list中第N位置为Key的tuple(只替换找到的第一个tuple)
lists:keystore(Key, N, TupleList1, NewTuple) -> TupleList2
12> lists:keystore(b,1,[{a,1,1},{b,1,1},{c,1,1}],{b,2,2}).
[{a,1,1},{b,2,2},{c,1,1}]
替换list中第N位置为Key的tuple,返回新的TupleList。没找不到将NewTuple附加到原有TupleList后面并返回,这是和lists:keyreplace/4的区别
注: 只替换找到的第一个tuple
lists函数小评
BIF函数
lists函数有一些已经被优化成bif函数,效率较高。有以下几个:
lists:member/2, lists:reverse/2, lists:keymember/3, lists:keysearch/3, lists:keyfind/3
性能不佳的函数
下面是一些实现性能不佳的函数,不建议比较长的list使用,短的list无所谓了:
1)lists:foldr/3
非尾递归实现,如果顺序很重要的话,可以lists:reverse/1后lists:foldl/3,或者lists:foldl/3后lists:reverse/1
lists:foldr类似lists:foldl,不同的是foldr从列表最后一个元素开始,非尾递归实现,不建议长列表使用
foldr(F, Accu, [Hd|Tail]) ->
F(Hd, foldr(F, Accu, Tail));
foldr(F, Accu, []) when is_function(F, 2) ->
Accu.
2)lists:append/2
实现为append(L1, L2) -> L1 ++ L2. 其中,L1 ++ L2会遍历 L1,如果一定要使用就把短的list放左边
3)lists:subtract/2
实现为subtract(L1, L2) -> L1 -- L2. 其中,--的复杂度和它的操作数的长度的乘积成正比,替代方案如下:
Set = gb_sets:from_list(L2),
[E || E <- L1, not gb_sets:is_element(E, Set)].
注:如果L1中包含重复的元素,那么以上代码跟--的效果不同,--不会删掉所有重复的元素
13> [1,2,3,4,2] -- [2,3].
[1,4,2]
4)lists:flatten/1
这个是list扁平化函数,这个存在性能开销,erlang的官方文档也有说明:
lists:flatten/1 builds an entirely new list. Therefore, it is expensive, and even more expensive than the ++ (which copies its left argument, but not its right argument).
它会拷贝DeepList中所有嵌套的元素,生成一个新的列表,代价比较高,长列表不建议使用。
flatten(List) when is_list(List) ->
do_flatten(List, []).
flatten(List, Tail) when is_list(List), is_list(Tail) ->
do_flatten(List, Tail).
do_flatten([H|T], Tail) when is_list(H) ->
do_flatten(H, do_flatten(T, Tail));
do_flatten([H|T], Tail) ->
[H|do_flatten(T, Tail)];
do_flatten([], Tail) ->
Tail.
5)lists中非尾递归实现的函数:
lists:map/2,lists:flatmap/2,lists:zip/2,lists:delete/2,lists:sublist/2, lists:sublist/3,lists:takewhile/2,lists:concat/1
lists:flatten/1,lists:keydelete/3, lists:keystore/4,lists:zf/2,lists:mapfoldl/3,lists:mapfoldr/3,lists:foldr/3
带匿名函数的lists函数
lists有很多函数都带有匿名函数的参数项,有以下几个函数:
lists:foldl/3, lists:foldr/3, lists:foreach/2, lists:sort/2, lists:usort/2,lists:merge/3, lists:umerge/3, lists:keymap/3, lists:flatmap/2
匿名函数的使用有什么问题呢?
普通函数在erlang编译期就做了优化,匿名函数则要在代码执行期动态生成,造成一定的消耗。虽然现在匿名函数的过程已优化成本地函数了,但根据上下文取值,地址跳转还是不能避免。可能以后erlang会继续对匿名函数做改进
对lists匿名函数的处理的优化:
1)函数赋值
第一个问题就是不要在循环中写这样的代码:
14> [lists:foldl(fun(X, Sum) -> X + Sum end, 0, [1,2,3,4,5]) || X <- lists:seq(1,5)].
[15,15,15,15,15]
以上代码中,每次循环匿名函数都会重新生成,可以如下修改:
17> Fun = fun(X, Sum) -> X + Sum end.
#Fun<erl_eval.12.82930912>
18> [lists:foldl(Fun, 0, [1,2,3,4,5]) || X <- lists:seq(1,5)].
[15,15,15,15,15]
匿名函数Fun只要生成一次,作为参数放到lists函数即可
2)函数实体化
所谓实体化就是把匿名函数写成本地函数,然后再作为参数传给lists函数,如下:
test() ->
lists:foldl(fun sum/2, 0, [1,2,3,4,5]).
sum(X, Sum) ->
X + Sum.
这里也有匿名函数动态生成的问题,有兴趣的可以打印汇编码看看具体情况
2015/4/22补充:经测试,这种方式效率稍微变低,原因是,每次调用时对比多一次函数调用[i_call_only_f ]
这里讨论另一种调用方式 fun M:F/A
test() ->
lists:foldl(fun ?MODULE:sum/2, 0, [1,2,3,4,5]).
sum(X, Sum) ->
X + Sum.
如果是这种调用,执行过程中,会先调用bif函数erlang:make_fun/3 找到这个导出函数的代码地址,然后生成匿名函数结构数据,再像函数外部调用一样执行代码。如果将匿名函数赋值,然后再执行,单算执行效率的话就要比前面两种高。不过整体计算是比较低效的,因为erlang:make_fun/3 是根据函数名,方法名,参数个数去查找导出函数表,导出函数表是哈希桶实现,还是有一点效率开销。
列表解析
说到lists,不得不说列表解析,在之前的文章也谈过列表解析。列表解析的基本形式如下:
[Expr(E) || E <- List]
简单的例子如下:
19> [X+1||X<-[1,2,3,4,5]].
[2,3,4,5,6]
在列表解析表达式中,|| 左边用以生成列表元素,相当于构造器;右边由赋值语句和条件语句构成,也可以只有赋值语句。实际上,列表解析在编译时会优化一个本地函数,没必要过于担心它的性能。
使用列表解析注意以下问题就好:
20> [X+1||X<-[1,2,3,4,5]],ok.
ok
在上面的例子中,erlang对列表解析做了优化,如果列表解析的结果明显不会被用到,列表根本不会被构建。在这里,列表解析后加个ok可以激活erlang的优化
list列表元素打乱
列表元素打乱,就是将列表中元素的顺序随机化,打乱原来的顺序。
方法很简单,如下:
shuffle(L) ->
List1 = [{random:uniform(), X} || X <- L],
List2 = lists:keysort(1, List1),
[E || {_, E} <- List2].
注:random:uniform() 的随机化种子放在进程字典中。为了提高随机化,以上函数调用前或调用进程启动时执行一次 random:seed(erlang:now())
2016/2/29 补充 list列表元素打乱
参考:http://blog.csdn.net/mycwq/article/details/32160581
http://www.erlang.org/doc/efficiency_guide/listHandling.html
分享到:
相关推荐
Erlang应用优化指南 Erlang应用优化指南
10. `keymap/3`:这个函数用于更新`TupleList1`中每个元组的第`N`个元素,使用`Fun`处理后的结果替换它。例如: ```erlang List1 = [{name, "zhangjing"}, {name, "zhangsan"}]. lists:keymap(fun(X) -> list_to_...
你可以使用protobuf在Erlang节点间交换消息,或者与其他支持protobuf的语言(如Java、Python等)进行通信。 7. **性能优化**:protobuf的优势在于其高效的序列化和反序列化算法,可以在保持数据紧凑的同时,快速地...
分布式Erlang使用虚拟机(VM)的克隆,使得构建大规模分布式系统变得简单。 ### 7. 错误处理与恢复 Erlang采用“let it crash”哲学,鼓励程序在遇到错误时立即崩溃,而不是尝试恢复。这样可以快速暴露问题,便于...
Erlang是一种面向并发的、强类型的编程语言,...总之,Erlang与MySQL的对接涉及了数据库驱动的选用和使用,以及Erlang对数据库操作的封装。理解这些基本概念和流程,有助于构建健壮的、数据库驱动的Erlang应用程序。
在使用Erlang进行开发时,你可能需要用到以下工具和概念: - **Rebar3**:Erlang的构建和依赖管理工具,帮助你组织项目结构、编译代码和管理依赖。 - **OTP(Open Telephony Platform)**:Erlang的核心库,包含...
Erlang22是Erlang的第22个主要版本,它包含了对语言特性的改进、性能优化以及一些新的库和工具。 在“erlang22最新下载包”中,提供的文件是`otp_src_22.1`,这表明这是一个源代码包,包含Erlang/OTP(开放电信平台...
- 为了获得最佳的性能和安全性,建议始终使用最新版本的Erlang/OTP,同时确保该版本与当前运行的RabbitMQ版本兼容。 - 定期检查RabbitMQ和Erlang的更新,以确保及时修补安全漏洞和修复已知问题。 - 在生产环境中,...
### 并发需求下的Scala及Erlang语言的比较与使用 在当今的高并发、大数据处理场景下,选择合适的编程语言对于系统性能至关重要。在众多编程语言中,Scala和Erlang因其强大的并发处理能力和函数式编程特性而受到关注...
**Erlang程序设计与入门** Erlang是一种并发、函数式编程语言,主要用于构建分布式、高可用性、容错性强的系统。它的设计灵感来源于电信行业的需求,由瑞典爱立信公司于1986年开发。Erlang以其独特的并发模型、轻量...
了解ERTS内存使用情况对于优化Erlang程序至关重要。 #### 8. 高可用性和故障恢复 Erlang的heart进程是系统监视器,它负责监测和恢复Erlang节点的故障。这个机制是Erlang高可用性的基础。 #### 9. 新增特性和更新 *...
7. **并发性能优化**:Erlang的并发性能优化涉及进程数量的控制、消息队列管理以及合理分配系统资源。这通常需要对Erlang的VM(Virtual Machine)和调度器有深入理解。 8. **Erlang与其他技术的集成**:Erlang可以...
在IT领域,Erlang是一种面向并发的、...总的来说,使用Erlang连接Elasticsearch客户端,可以帮助开发者高效地与ES服务器交互,利用Erlang的强大并发性和函数式编程特性,实现稳定、高性能的搜索和数据分析解决方案。
6. **性能优化**:通过解决实际问题,学习者可以学习到如何有效地利用Erlang的特性进行性能优化,比如避免全局状态,利用并行计算等。 综上所述,"xiandiao"文件夹中的源码是学习Erlang编程和理解其并发特性的宝贵...
安装过程中,你可能会被询问是否要添加Erlang环境变量到PATH,这个选项建议选中,以便在命令行中可以直接使用erl命令。此外,安装路径的选择也很关键,最好选择一个不会频繁变动的位置,以避免日后升级或重装带来的...
5. **REPL(Read-Eval-Print Loop)**:Erlang shell的使用,它是学习和测试Erlang代码的重要工具。 6. **实际应用案例**:可能包含Erlang在实时系统、网络通信、数据库或Web服务等领域的应用示例。 这两本书结合...
总的来说,这个项目是为了验证和优化 Erlang 在 Linux 环境下通过 Port Driver 与外部程序交互的能力,测试可能涵盖了端口的创建、数据交换、错误处理和资源管理等多个方面。通过这样的测试,开发者可以确保他们的...
这两个模型由丹麦工程师Agner Krarup Erlang在20世纪初提出,至今仍广泛应用于现代通信网络的设计与优化。 Erlang B模型,也称为无阻塞模型,主要用于计算在给定呼叫到达率和系统容量下,系统不发生阻塞的概率。它...
6. **性能优化**:提供关于如何最大限度地提高CNode与Erlang节点之间通信效率的提示和最佳实践。 7. **案例研究和示例代码**:提供实际的应用场景和代码示例,帮助用户更好地理解和应用CNode技术。 **更多erlang...
学习erlang的时候尝试编写的小例子,使用post方式发送json数据来进行http请求,希望能帮到大家~