原文链接: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] 高效指南 -- 列表解析相关推荐

  1. Python-各种结构解析以及生成器(列表解析,字典解析,集合解析,元组构成的生成器)

    1.列表解析: 举例:生成一个列表,元素0-9,对每一个元素自增1后求平方返回新列表. test = [ (i + 1) ** 2 for i in range(10)] print(test) # ...

  2. Python学习小结---粗略列表解析

    列表解析 本文旨在说明列表解析的用法 Python是一门简单高效的语言,因此代码也可以变得简单高效,主要目的的利于阅读,方便书写.因此引入了许多语法糖.列表解析就是个例子. 传统方式的for循环: a ...

  3. Python(五)之迭代器和列表解析

    Python迭代器和列表解析 迭代器 例如:In [1]: l1 = [1,2,3,4,5]dir(i1)可以看到内置方法'__iter__'生成一个迭代器:l1.__iter__,或i2 = ite ...

  4. 列表解析和生成器表达式

    列表解析(List comprehensions,或者缩略为list comps)来自函数式编程语言Haskell,可以用来动态创建列表. [expr for iter_var in iterable ...

  5. 不会但一定要了解的方面,python列表解析方式

    Python支持各种解析(comprehension)操作,比如列表解析.集合解析.元组解析.字典解析.它们根据某些元素来创建(推导)出一个新的列表.集合.元组.字典等.所以有的地方也称为推导,比如列 ...

  6. Python基础教程:列表解析

    Python中的解析 Python支持各种解析(comprehension)操作,比如列表解析.集合解析.元组解析.字典解析.它们根据某些元素来创建(推导)出一个新的列表.集合.元组.字典等.所以有的 ...

  7. python学习-列表解析、字典解析

    文章目录 扩展链接 列表解析 字典解析 扩展链接 一些基础数据类型的博文链接: python学习-数据类型 列表 python学习-数据类型 字典 python学习-数据类型 元组 python学习- ...

  8. json解析和字符串解析_高效创建和解析定界字符串

    json解析和字符串解析 描述 (Description) Converting a delimited string into a dataset or transforming it into u ...

  9. python列表迭代器_Python 迭代器之列表解析

     尽管while和for循环能够执行大多数重复性任务, 但是由于序列的迭代需求如此常见和广泛, 以至于Python提供了额外的工具以使其更简单和高效. 迭代器在Python中是以C语言的速度运行的, ...

最新文章

  1. Python xrange() 函数
  2. 再迎利好,BCH开发团队BU融合石墨烯区块传播技术
  3. linux下定时器实现
  4. Linux中相关知识(atexit(),fork(),粘滞位)
  5. java 判断两个数是否异号
  6. (38)Gulp任务完整组合写法
  7. c语言中open函数r,C语言中open函数
  8. html状态栏透明,HTML – 如何使我的导航栏略微透明?
  9. 张果老能是鸿蒙时期一蝙蝠,张果老(中国古代神话传说八仙之一)_百度百科...
  10. wgs84坐标系拾取工具_Wgs84坐标系转换为gcj02坐标系及bd09坐标系的验证
  11. 语音识别-语音技术-自然语言处理
  12. 使用谷歌API将任意语言翻译成英文
  13. 计算机分区硬盘有写保护,磁盘被写保护怎么办?总结几种去掉磁盘写保护的方法...
  14. 年龄识别之ssrnet
  15. 软考(14)-接入网技术-sonet/sdh
  16. latex beamer 制作ppt,包括动画效果。插入gif图
  17. oracle灾备同步_浅析Oracle数据库的三种灾备技术
  18. Android字体样式修改
  19. 【三维目标分类 】PointNet详解(一)
  20. Microsoft Office自制安装指南 —Nusen_Liu

热门文章

  1. 秘钥对使用_使用gitactions持续集成项目实例
  2. Syn Bot /OSCOVA 上下文(8)
  3. 结对编程项目作业-结对编项目设计文档
  4. 关于大型站点技术演进的思考(七)--存储的瓶颈(7)
  5. Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) E. DNA Evolution 树状数组
  6. 微信小程序 -字体图标
  7. wince6.0 编译报错:error C2220: warning treated as error - no 'object' file generated的解决办法...
  8. Apache运行机制剖析
  9. 2010有道难题练习赛2
  10. linux命令0424