[Erlang-0006][OTP] 高效指南 -- 列表解析
原文链接:http://www.erlang.org/doc/efficiency_guide/listHandling.html
水平有限,错误之处欢迎指正。
5 列表解析
5.1 创建一个列表
创建列表最好从最后开始,一个元素接一个元素地附加在前面。如果你用++操作符:
List1 ++ List2
会通过把List1拷贝一份附加在List2前面来创建一个新的列表。看一下lists:append/1或者++在Erlang里是如何实现的,我们可以清楚地看到第一个列表被拷贝。
append([H|T], Tail) ->[H|append(T, Tail)]; append([], Tail) ->Tail.
所以当递归或者创建列表时要注意的是,确保把元素放到列表的前面,以便你创建列表时,随着列表的生成,不会有成百上千的拷贝。
先让我们看看不鼓励的做法:
bad_fib(N) ->bad_fib(N, 0, 1, []).bad_fib(0, _Current, _Next, Fibs) ->Fibs; bad_fib(N, Current, Next, Fibs) -> bad_fib(N - 1, Next, Current + Next, Fibs ++ [Current]).
这里我不是创建了一个列表,每次迭代我们创建了一个新的列表,只比上一个多一个元素。
避免每次迭代都要拷贝结果,我们必须反序创建列表,在最后反转之:
DO
tail_recursive_fib(N) ->tail_recursive_fib(N, 0, 1, []).tail_recursive_fib(0, _Current, _Next, Fibs) ->lists:reverse(Fibs); tail_recursive_fib(N, Current, Next, Fibs) -> tail_recursive_fib(N - 1, Next, Current + Next, [Current|Fibs]).
5.2 列表解析
列表解析依然被误认为很慢。它们过去是用funs实现的,funs之前很慢。
在当前Erlang/OTP版本(包括R12B),列表解析
[Expr(E) || E <- List]
基本上被解析成一个本地函数
'lc^0'([E|Tail], Expr) ->[Expr(E)|'lc^0'(Tail, Expr)]; 'lc^0'([], _Expr) -> [].
在R12B中,如果列表解析的结果明显地不会被用到,列表根本不会被构建。例如下面的代码
[io:put_chars(E) || E <- List], ok.
或者这样的代码
. . . case Var of... ->[io:put_chars(E) || E <- List];... -> end, some_function(...), . . .
结果既不付给变量又不传给另一个函数,也不是返回值,那么就没有必要构建列表,编译器会简化这个列表解析成
'lc^0'([E|Tail], Expr) ->Expr(E),'lc^0'(Tail, Expr); 'lc^0'([], _Expr) -> [].
5.3 嵌套和拉伸列表
lists:flatten/1创建一个全新的列表,因此,代价比较高,甚至比++还要高(++只会拷贝左边的列表,右边的不拷贝)。
以下情况可以避免使用lists:flatten/1:
a. 向端口发送数据。端口能够处理嵌套列表,所以不须在发送前拉平列表。
b. 调用BIFs接收嵌套列表,例如list_to_binary/1或iolist_to_binary/1。
c. 当你的列表只有一层嵌套的时候,可以用lists:append/1。
Port example
DO
... port_command(Port, DeepList) ...
DO NOT
... port_command(Port, lists:flatten(DeepList)) ...
通常会这样向端口发送一个以0为结尾的字符串:
DO NOT
... TerminatedStr = String ++ [0], % String="foo" => [$f, $o, $o, 0] port_command(Port, TerminatedStr) ...
可以用这种方式来代替:
DO
... TerminatedStr = [String, 0], % String="foo" => [[$f, $o, $o], 0] port_command(Port, TerminatedStr) ...
Append example
DO
> lists:append([[1], [2], [3]]). [1,2,3] >
DO NOT
> lists:flatten([[1], [2], [3]]). [1,2,3] >
5.4 为什么不必担心通过列表来递归的函数
在性能谬论那一章,下面这条谎言被揭穿:尾递归函数比递归函数快很多。
总的来说,在R12B里通常一个列表递归函数和尾递归加反转没有太大差别。因此,大多数情况下应该忽略列表函数的性能,重点关注代码的整洁。只有在运行时间要求严格的那一小段代码需要特殊照顾,并且在重写它们之前一定要测试。
重要提示:这一节谈论的列表函数都会构建列表。尾递归函数只需要恒定的空间运行,不用构建新的列表,而递归函数用到的栈空间和列表的长度成正比。例如,求和一个整数列表的函数不应该这样写
DO NOT
recursive_sum([H|T]) -> H+recursive_sum(T); recursive_sum([]) -> 0.
而应该
DO
sum(L) -> sum(L, 0).sum([H|T], Sum) -> sum(T, Sum + H); sum([], Sum) -> Sum.
原创翻译,欢迎任何形式的转载,但请务必注明出处:http://www.cnblogs.com/liangjingyang
转载于:https://www.cnblogs.com/liangjingyang/archive/2012/07/15/2592691.html
[Erlang-0006][OTP] 高效指南 -- 列表解析相关推荐
- Python-各种结构解析以及生成器(列表解析,字典解析,集合解析,元组构成的生成器)
1.列表解析: 举例:生成一个列表,元素0-9,对每一个元素自增1后求平方返回新列表. test = [ (i + 1) ** 2 for i in range(10)] print(test) # ...
- Python学习小结---粗略列表解析
列表解析 本文旨在说明列表解析的用法 Python是一门简单高效的语言,因此代码也可以变得简单高效,主要目的的利于阅读,方便书写.因此引入了许多语法糖.列表解析就是个例子. 传统方式的for循环: a ...
- Python(五)之迭代器和列表解析
Python迭代器和列表解析 迭代器 例如:In [1]: l1 = [1,2,3,4,5]dir(i1)可以看到内置方法'__iter__'生成一个迭代器:l1.__iter__,或i2 = ite ...
- 列表解析和生成器表达式
列表解析(List comprehensions,或者缩略为list comps)来自函数式编程语言Haskell,可以用来动态创建列表. [expr for iter_var in iterable ...
- 不会但一定要了解的方面,python列表解析方式
Python支持各种解析(comprehension)操作,比如列表解析.集合解析.元组解析.字典解析.它们根据某些元素来创建(推导)出一个新的列表.集合.元组.字典等.所以有的地方也称为推导,比如列 ...
- Python基础教程:列表解析
Python中的解析 Python支持各种解析(comprehension)操作,比如列表解析.集合解析.元组解析.字典解析.它们根据某些元素来创建(推导)出一个新的列表.集合.元组.字典等.所以有的 ...
- python学习-列表解析、字典解析
文章目录 扩展链接 列表解析 字典解析 扩展链接 一些基础数据类型的博文链接: python学习-数据类型 列表 python学习-数据类型 字典 python学习-数据类型 元组 python学习- ...
- json解析和字符串解析_高效创建和解析定界字符串
json解析和字符串解析 描述 (Description) Converting a delimited string into a dataset or transforming it into u ...
- python列表迭代器_Python 迭代器之列表解析
 尽管while和for循环能够执行大多数重复性任务, 但是由于序列的迭代需求如此常见和广泛, 以至于Python提供了额外的工具以使其更简单和高效. 迭代器在Python中是以C语言的速度运行的, ...
最新文章
- Python xrange() 函数
- 再迎利好,BCH开发团队BU融合石墨烯区块传播技术
- linux下定时器实现
- Linux中相关知识(atexit(),fork(),粘滞位)
- java 判断两个数是否异号
- (38)Gulp任务完整组合写法
- c语言中open函数r,C语言中open函数
- html状态栏透明,HTML – 如何使我的导航栏略微透明?
- 张果老能是鸿蒙时期一蝙蝠,张果老(中国古代神话传说八仙之一)_百度百科...
- wgs84坐标系拾取工具_Wgs84坐标系转换为gcj02坐标系及bd09坐标系的验证
- 语音识别-语音技术-自然语言处理
- 使用谷歌API将任意语言翻译成英文
- 计算机分区硬盘有写保护,磁盘被写保护怎么办?总结几种去掉磁盘写保护的方法...
- 年龄识别之ssrnet
- 软考(14)-接入网技术-sonet/sdh
- latex beamer 制作ppt,包括动画效果。插入gif图
- oracle灾备同步_浅析Oracle数据库的三种灾备技术
- Android字体样式修改
- 【三维目标分类 】PointNet详解(一)
- Microsoft Office自制安装指南 —Nusen_Liu
热门文章
- 秘钥对使用_使用gitactions持续集成项目实例
- Syn Bot /OSCOVA 上下文(8)
- 结对编程项目作业-结对编项目设计文档
- 关于大型站点技术演进的思考(七)--存储的瓶颈(7)
- Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) E. DNA Evolution 树状数组
- 微信小程序 -字体图标
- wince6.0 编译报错:error C2220: warning treated as error - no 'object' file generated的解决办法...
- Apache运行机制剖析
- 2010有道难题练习赛2
- linux命令0424