proplists 模块适用数据量较少的场景,处理配置文件和函数选项时常用.proplists对内部数据结构是Key-Value键值对形式,第一个元素做key用来查询和删除,如果一个key有多个值就会使用第一次出现的值,其它被忽略.proplists对于Key和Value的约束极其宽松,可以是任意term().甚至可以把{Atom,true}缩写成为Atom.也正是由于这样宽松的数据约束,proplists模块没有更新和追加数据项的方法,需要使用lists:replace/4.Key进行比较使用的是=:=精确等于,会判断类型和值.
 
 
  1. 5> proplists:get_value(1,[{1,a},{1.0,b},{1,c}]).
  2. a
  3. 6> proplists:append_values(1,[{1,a},{1.0,b},{1,c}]).
  4. [a,c]
  5. 8>

规范与压缩

  上面提到Atom缩写的形式,atom的形式成为压缩格式,{Atom,true}的形式成为规范形式.这是Property的两种形式,其定义是 -type property()   :: atom() | tuple().
模块里面有一个property方法专门进行数据规范化.
  1. property({Key, true}) when is_atom(Key) ->
  2. Key;
  3. property(Property) ->
  4. Property.
  5. 调用的形式:
  6. 16> proplists:property({a}).
  7. {a}
  8. 17> proplists:property({a,true}).
  9. a
压缩形式其实就是逐一对proplists内的元素执行property/1,即:[property(P) || P <- List].
  1. 10> proplists:compact( [{a, true}, {b, true}, {a, 3}, {c, true}, {a, [4]}]).
  2. [a,b,{a,3},c,{a,[4]}]
计算有压缩就会有展开的函数
  1. unfold([P | Ps]) ->
  2. if is_atom(P) ->
  3. [{P, true} | unfold(Ps)];
  4. true ->
  5. [P | unfold(Ps)]
  6. end;
  7. unfold([]) ->
  8. [].
  9.  
  10. 12> proplists:unfold([foo,bar,test,haha]).
  11. [{foo,true},{bar,true},{test,true},{haha,true}]
  12. 13> proplists:unfold([foo,bar,{test,false},haha]).
  13. [{foo,true},{bar,true},{test,false},{haha,true}]
  14. 14> proplists:unfold([foo,"zen",bar,{test,false},haha]).
  15. [{foo,true},"zen",{bar,true},{test,false},{haha,true}]
  16. 15> proplists:unfold([foo,"zen",23,{test,false},haha]).
  17. [{foo,true},"zen",23,{test,false},{haha,true}]
 

proplists 相关操作

下面看一下proplists的常规操作,有一些方法还是要注意一下细节的.

 append_values (注意上图中少拼写了一个s )将所有key值相同的数据项,value整合在list中.
  1. 1> proplists:append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}]).
  2. [1,2,3,4]
  3. 2> proplists:append_values(a, [{a, b}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}]).
  4. [b,3,4]
  5. 3> proplists:append_values(a, [{a, b}, {b, 0}, {a, 3}, {c, -1}, {a, [[4]]}]).
  6. [b,3,[4]]
  7.  
  8. 1> proplists:append_values(a, [{a, [1,2]}, {"zen", 0}, {a, 3}, {c, -1}, {a, [4]}
  9. ]).
  10. [1,2,3,4]
  11. 2> proplists:append_values(a, [{a, [1,2]},b]).
  12. [1,2]
  13. 3> proplists:append_values(b, [{a, [1,2]},b]).
  14. [true]
  15. 4>
 
delete方法会删除所有等于Key值的数据项:
  1. %% delete(Key, List) -> List
  2. 18> proplists:delete(a, [{a, true}, {b, true}, {a, 3}, {c, true}, {a, [4]}]).
  3. [{b,true},{c,true}]
 
compact将数据进行压缩
  1. 10> proplists:compact( [{a, true}, {b, true}, {a, 3}, {c, true}, {a, [4]}]).
  2. [a,b,{a,3},c,{a,[4]}]

 

get_all_values 获取所有等于Key值的数据项:

  1. 8> proplists:get_all_values(a, [{a, [1,2]}, {"zen", 0}, {a, 3}, {c, -1}, {a, [4]
  2. }]).
  3. [[1,2],3,[4]]
  4. 9>
get_bool 这个方法还是有点陷阱的,其意图是看Key值第一次出现时的值是true|false. 
  1. get_bool(Key, [P | Ps]) ->
  2. if is_atom(P), P =:= Key -> true;
  3.  
  4. tuple_size(P) >= 1, element(1, P) =:= Key ->
  5. case P of
  6. {_, true} ->
  7. true;
  8. _ ->
  9. %% Don't continue the search!
  10. false
  11. end;
  12. true ->
  13. get_bool(Key, Ps)
  14. end;
  15. get_bool(_Key, []) ->
  16. false.
  17.  
  18. 9> proplists:get_bool(a, [{a, [1,2]}, {"zen", 0}, {a, 3}, {c, -1}, {a, [4]}]).
  19. false
  20. 10> proplists:get_bool(a, [{a, [1,2]}, {"zen", 0}, {a, 3},a, {c, -1}, {a, [4]}]).
  21. false
  22. 11> proplists:get_bool(a, [a,{a, [1,2]}, {"zen", 0}, {a, 3},a, {c, -1}, {a, [4]}]).
  23. true
  24. 12> proplists:get_bool(a, [{a,true},{a, [1,2]}, {"zen", 0}, {a, 3},a, {c, -1}, {a, [4]}]).
  25. true
  26. 13> proplists:get_bool(a, [{a,false},{a, [1,2]}, {"zen", 0}, {a, 3},a, {c, -1},{a, [4]}]).
  27. false
  28. 14> proplists:get_bool(q, [{a,true},{a, [1,2]}, {"zen", 0}, {a, 3},a, {c, -1}, {a, [4]}]).
  29. false
  30. 15> proplists:get_bool(q, ["abc",{a,true},{a, [1,2]}, {"zen", 0}, {a, 3},a, {c,-1}, {a, [4]}]).
  31. false
  32. 16> proplists:get_bool("abc", ["abc",{a,true},{a, [1,2]}, {"zen", 0}, {a, 3},a,{c, -1}, {a, [4]}]).
  33. false
  34. 17> proplists:get_bool("abc", [{"abc",true},{a,true},{a, [1,2]}, {"zen", 0}, {a,
  35. 3},a, {c, -1}, {a, [4]}]).
  36. true
 get_keys 获取所有不重复的keys
  1. 18> proplists:get_keys([{"abc",true},{a,true},{a, [1,2]}, {"zen", 0}, {a, 3},a,{c, -1}, {a, [4]}]).
  2. ["zen",a,c,"abc"]
  3. 19> proplists:get_keys([{a,true},{a,true},{a, [1,2]}, {"zen", 0}, {a, 3},a, {c,-1}, {a, [4]}]).
  4. ["zen",a,c]
get_value 按Key取值,取得是第一次出现的Value
  1. get_value(Key, [P | Ps], Default) ->
  2. if is_atom(P), P =:= Key ->
  3. true;
  4. tuple_size(P) >= 1, element(1, P) =:= Key ->
  5. case P of
  6. {_, Value} ->
  7. Value;
  8. _ ->
  9. %% Don</code>t continue the search!
  10. Default
  11. end;
  12. true ->
  13. get_value(Key, Ps, Default)
  14. end;
  15. get_value(_Key, [], Default) ->
  16. Default.
  17.  
  18. 3> proplists:get_value([a,b], ["packet",[a,b],"login",22,2,s,f] , "none").
  19. "none"
  20. 4> proplists:get_value("login", ["packet",[a,b],"login",22,2,s,f] , "none").
  21. "none"
  22. 5> proplists:get_value(login, ["packet",[a,b],"login",22,2,s,f] , "none").
  23. "none"
  24.  
  25. 1> proplists:get_value([a,b], ["packet",{[a,b],bingo},"login",22,2,s,f] , "none").
  26. bingo
  27. 2> proplists:get_value(s, ["packet",{[a,b],bingo},"login",22,2,s,f] , "none").
  28. true
  29. 3>
look_up 与get_value不同的是这里返回的是{Key,Value}
  1. 6> proplists:lookup(a, [{a, b}, {b, 0}, {a, 3}, {c, -1}, {a, [[4]]}]).
  2. {a,b}
  3. 7> proplists:lookup(a, [{a,1},{a, b}, {b, 0}, {a, 3}, {c, -1}, {a, [[4]]}]).
  4. {a,1}
  5. 8>
lookup_all 
  1. 8> proplists:lookup_all(a, [{a,1},{a, b}, {b, 0}, {a, 3}, {c, -1}, {a, [[4]]}]).
  2. [{a,1},{a,b},{a,3},{a,[[4]]}]
 
is_defined 是否存在特定Key值
  1. 6> proplists:is_defined(s, ["packet",{s,kill},{[a,b],bingo},"login",22,2,s,f]).
  2. true
  3. 7> proplists:is_defined(p, ["packet",{s,kill},{[a,b],bingo},"login",22,2,s,f]).
  4. false
  5. 8>
split 按照Key值进行数据分组
  1. 9> proplists:split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c]).
  2. {[[a],[{b,5},b],[{c,2},{c,3,4}]],[{e,1},d]}
  3. 10> proplists:split([{c, 2}, {c,23},{a,false},{e, 1}, a, {c, 3, 4}, d, {b, 5}, b
  4. ], [a, b, c]).
  5. {[[{a,false},a],[{b,5},b],[{c,2},{c,23},{c,3,4}]],[{e,1},d]}
  6. 11>

单独一组

下面这几个方法我们放在一起看
 
 expand 做的是把list中的Key替换成对应Value ,注意, 这个方法展开的对象是Property
  1. 8> proplists: expand([{foo, [bar, baz]}],[fie, foo, fum]).
  2. [fie,bar,baz,fum]
  3. 9> proplists: expand([{foo, [bar, baz]},{fie,ok},{fum,100}],[fie, foo, fum]).
  4. [ok,bar,baz,100]
  5. 10> proplists: expand([{foo, [bar, baz]},{fie,[[ok]]},{fum,"100"}],[fie, foo, fum]).
  6. [[ok],bar,baz,49,48,48]
  7.  
  8. 12> proplists: expand([{"fie",23},{1,{1}},{1.0,{29}},{foo, [bar, baz]},{fie,[[ok]]},{fum,"100"}],["fie",1, foo, fum]).
  9. [102,105,101,1,bar,baz,49,48,48]
  10. 13> ${.
  11. 123
  12. 14> [102,105,101].
  13. "fie"
  14. 15>
 substitute_aliases 将对应的key值替换为别名
  1. 1> proplists:substitute_aliases([{zen,"ligaoren"},{0,zero}],[zen,{zen,zen},{abc,zen},{zen,tick},0,{0,1},{23,0}]).
  2. [{"ligaoren",true},{"ligaoren",zen},{abc,zen},{"ligaoren",tick},0,{zero,1},{23,0}]
  3. 2>
substitute_negations key值替换,value取反
  1. 2> proplists:substitute_negations([{zen,"ligaoren"},{0,zero}],[zen,{zen,zen},{abc,zen},{zen,tick},0,{0,1},{23,0}]).
  2. [{"ligaoren",false},{"ligaoren",true},{abc,zen},{"ligaoren",true},0,zero,{23,0}]
  3.  
  4. 3> proplists:substitute_negations([{zen,"ligaoren"},{0,zero}],[zen,{zen,zen},{abc,zen},{zen,tick},0,{0,true},{23,0}]).
  5. [{"ligaoren",false},{"ligaoren",true},{abc,zen},{"ligaoren",true},0,{zero,false},{23,0}]
  6.  
  7. 4> proplists:substitute_negations([{zen,"ligaoren"},{0,zero}],[zen,{zen,zen},{abc,zen},{zen,tick},0,{0,false},{23,0}]).
  8. [{"ligaoren",false},{"ligaoren",true},{abc,zen},{"ligaoren",true},0,zero,{23,0}]
 normalize 整合了substitute_aliases   substitute_negations  expand
  1. 2> proplists:normalize( [a,b,c,d,e,f,g],[{aliases, [{b,b2},{e,email}]} ]).
  2. [a,b2,c,d,email,f,g]
  3. 3> proplists:normalize([a,b,c,d,e,f,g],[{aliases, [{b,b2},{e,email}]} ]).
  4. [a,b2,c,d,email,f,g]
  5. 4> proplists:normalize([a,b,c,d,e,f,g],[{aliases, [ {negations, [a,f]}]} ]).
  6. [a,b,c,d,e,f,g]
  7. 5> proplists:normalize([a,b,c,d,e,f,g],[ {expand, [{d,do_it_by_yourself},{g,1000}]}]).
  8. [a,b,c,do_it_by_yourself,e,f,1000]

应用举例

  1. 6> test:module_info(compile).
  2. [{options,[{outdir,"/zen/temp"}]},
  3. {version,"4.8"},
  4. {time,{2012,6,15,2,3,23}},
  5. {source,"/zen/temp/test.erl"}]
  6. 7> proplists:get_value(time,test:module_info(compile)).
  7. {2012,6,15,2,3,23}
  8. 8>
 
mochiweb项目解析Header Cookie多处使用了proplist: 
  1. parse_form_outer(eof, _, Acc) ->
  2. lists:reverse(Acc);
  3. parse_form_outer({headers, H}, FileHandler, State) ->
  4. {"form-data", H1} = proplists:get_value("content-disposition", H),
  5. Name = proplists:get_value("name", H1),
  6. Filename = proplists:get_value("filename", H1),
  7. case Filename of
  8. undefined ->
  9. fun (Next) ->
  10. parse_form_value(Next, {Name, []}, FileHandler, State)
  11. end;
  12. _ ->
  13. ContentType = proplists:get_value("content-type", H),
  14. Handler = FileHandler(Filename, ContentType),
  15. fun (Next) ->
  16. parse_form_file(Next, {Name, Handler}, FileHandler, State)
  17. end
  18. end.

解析选项一例:

  1. %%% 18> proplists:lookup(loop,[{ip, "127.0.0.1"},{loop, {mochiweb_http, default_body}}]).
  2. %%% {loop,{mochiweb_http,default_body}}
  3.  
  4. parse_options(Options) ->
  5. {loop, HttpLoop} = proplists:lookup(loop, Options),
  6. Loop = fun (S) ->
  7. ?MODULE:loop(S, HttpLoop)
  8. end,
  9. Options1 = [{loop, Loop} | proplists:delete(loop, Options)],
  10. mochilists:set_defaults(?DEFAULTS, Options1).

最后:估计90%的情况下,我们只使用proplists:get_value   : )

2012-8-22更新

proplists:get_value的性能要比lists:keyfind差很多,

lists的下面几个方法都是BIF实现:%% Bifs: keymember/3, keysearch/3, keyfind/3

而proplists:get_value是Erlang实现,我觉得这是产生性能差异的根本原因;

下面有一个相关讨论基本上是同样的判断: http://www.ostinelli.net/erlang-listskeyfind-or-proplistsget_value/

  1. -module(pvsl).
  2. -define(LIST_SIZES, [10000, 100000, 1000000]).
  3. -define(RETRIES, 1000).
  4. -compile(export_all).
  5.  
  6. start() ->
  7. % test for different list sizes
  8. lists:foreach(fun(N) -> test_list(N) end, ?LIST_SIZES).
  9.  
  10. test_list(ListSize) ->
  11. % generate a list of size ListSize of {Key, Val} entries
  12. KeyList = [{K, K} || K <- lists:seq(1, ListSize)],
  13. % test this list against both functions
  14. lists:foreach(fun(Type) -> get_val(Type, now(), KeyList, ListSize, ?RETRIES) end,
  15. [proplists, lists]).
  16.  
  17. % test getting values, compute necessary time and output print results
  18. get_val(Type, Start, _KeyList, ListSize, 0) ->
  19. T = timer:now_diff(now(), Start),
  20. io:format("computed ~p random key searches on a ~p-sized list in ~p ms using ~p~n",
  21. [?RETRIES, ListSize, T/1000, Type]);
  22. get_val(proplists, Start, KeyList, ListSize, Tries) ->
  23. proplists:get_value(random:uniform(ListSize), KeyList),
  24. get_val(proplists, Start, KeyList, ListSize, Tries - 1);
  25. get_val(lists, Start, KeyList, ListSize, Tries) ->
  26. lists:keyfind(random:uniform(ListSize), 1, KeyList),
  27. get_val(lists, Start, KeyList, ListSize, Tries - 1).
  28.  
  29. I ran this test on my MacBook Pro, Intel Core i5 2.4GHz with 4GB Memory, and Erlang R13B04, with Kernel Polling enabled. These are the results.
  30. roberto$ erl +K true +P 1000000
  31. Erlang R13B04 (erts-5.7.5) [source] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:true]
  32.  
  33. Eshell V5.7.5 (abort with ^G)
  34. 1> c(pvsl).
  35. {ok,pvsl}
  36. 2> pvsl:start().
  37. computed 1000 random key searches on a 10000-sized list in 323.373 ms using proplists
  38. computed 1000 random key searches on a 10000-sized list in 12.897 ms using lists
  39. computed 1000 random key searches on a 100000-sized list in 3273.973 ms using proplists
  40. computed 1000 random key searches on a 100000-sized list in 130.592 ms using lists
  41. computed 1000 random key searches on a 1000000-sized list in 34131.905 ms using proplists
  42. computed 1000 random key searches on a 1000000-sized list in 2050.627 ms using lists
  43. ok
  44. 3>

Erlang--proplists结构解析的更多相关文章

  1. iOS沙盒目录结构解析

    iOS沙盒目录结构解析 原文地址:http://blog.csdn.net/wzzvictory/article/details/18269713     出于安全考虑,iOS系统的沙盒机制规定每个应 ...

  2. H.264码流结构解析

    from:http://wenku.baidu.com/link?url=hYQHJcAWUIS-8C7nSBbf-8lGagYGXKb5msVwQKWyXFAcPLU5gR4BKOVLrFOw4bX ...

  3. Oracle的rowid结构解析

    SQL> select rowid,deptno from dept; ROWID                  DEPTNO ------------------ ---------- A ...

  4. EXT 结构解析

    EXT Demo 结构解析 创建项目 sencha -sdk F:\lib\ext-6.0.0 generate app demo F:\demo 预览项目 执行命令 sencha app build ...

  5. ionic项目结构解析

    ionic项目结构解析 原始结构 创建一个IonicDemo项目 'ionic start IonicDemo sidemenu' 这种结构多模块开发比较麻烦,因为view跟controller分开路 ...

  6. Redis源码剖析--源码结构解析

    请持续关注我的个人博客:https://zcheng.ren 找工作那会儿,看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识.在面试过程中,redis确实 ...

  7. InfluxDB源码目录结构解析

    操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 influxdata主目录结构 [root@localhost ...

  8. [转帖]认识固态:SSD硬盘内外结构解析

    认识固态:SSD硬盘内外结构解析 来自: 中关村在线 收藏 分享 邀请 固态硬盘(Solid State Drive),简称固态盘(SSD),是用固态电子存储芯片阵列而制成的硬盘,由控制单元和存储单元 ...

  9. redis源代码结构解析

    看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识: 之前面试的时候被问到了这部分的内容,没有关注,好在还有时间,就把Redis的源码看了一遍. Redis ...

  10. MBR结构解析与fdisk的bash实现

    一.MBR结构解析 首先我们先介绍一些MBR的基本知识基础,再晾图片分析. MBR主要分为三大块各自是: 1.载入引导程序(446K) 2.分区表(64k) 3.标志结束位(2k) 载入引导程序:内容 ...

随机推荐

  1. javascript 基础

    javascript概述: javascript历史: * 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEas ...

  2. Chrome 开发工具之Network

    经常会听到比如"为什么我的js代码没执行啊?","我明明发送了请求,为什么反应?","我这个网站怎么加载的这么慢?"这类的问题,那么问题既然 ...

  3. BZOJ1923: [Sdoi2010]外星千足虫

    传送门 高斯消元求解Xor方程. 这个方程很容易换成xor的方程.然后用高斯消元搞就行了. 用bitset实现这个非常方便. //BZOJ 1923 //by Cydiater //2016.11.3 ...

  4. logstash-5.0同步mysql

    环境 Windows10企业版X64 安装logstash-input-jdbc插件 进入logstash/bin/目录,命令: logstash-plugin install logstash-in ...

  5. React项目(二):生命游戏

    引子 这是16年最后的一个练手项目,一贯的感觉就是,做项目容易,写说明文档难.更何况是一个唤起抑郁感觉的项目,码下的每个字,心就如加了一个千斤的砝码. 2016年,有些事我都已忘记,但我现在还记得.2 ...

  6. Python连接MySQL

    win10.Python2.7.Pycharm import MySQLdb conn = MySQLdb.Connect( host = '127.0.0.1', port = 3306, user ...

  7. 欢迎来到Joyful Physics博客

    本博客主要包括以下内容: 物理课程 预计会涵盖非物理专业普通物理.物理专业普通物理.理论物理(四大力学).凝聚态物理,会特别关注软物质物理,因为博主是做软物质物理的. 软硬科普 软科普写给非专业人士. ...

  8. Template function 函数模板用法

    #include<iostream> using namespace std; const double PI = 3.1415926; template <class T> ...

  9. C#发送邮件异常:根据验证过程,远程证书无效

    今天在做发送邮件功能时,开始用qq邮箱和163邮箱都可以正常发送,后再改用我公司的邮箱和smtp时竟然报错了. 异常提示-----"根据验证过程,远程证书无效",后来通过查询资料解 ...

  10. WPF中弹出菜单

    在WPF里弹出菜单是用Popup,你那个右键的是上下文菜单(也就是快捷菜单). <Grid> <Button x:Name="BtnPop" Width=&quo ...