.. include:: ../include/substitution.rst .. highlight:: erlang :linenothreshold: 3 ************** 第3ç« åˆ—è¡¨ç¼–ç¨‹ ************** :翻译: 连城 è¿™ä¸€ç« ç ”ç©¶å¯¹åˆ—è¡¨çš„å¤„ç†ã€‚列表是用于å˜å‚¨å¯å˜æ•°é‡çš„å…ƒç´ çš„ç»“æž„ã€‚åˆ—è¡¨çš„å†™æ³•ä»¥â€œ\ ``[``\ â€å¼€å¤´ä»¥â€œ\ ``]``\ â€ç»“å°¾ã€‚åˆ—è¡¨çš„å…ƒç´ ä»¥é€—å·åˆ†éš”。例如,\ ``[E1,E2,E3,...]``\ 指代包å«å…ƒç´ \ ``E1,E2,E3,...``\ 的列表。 æ ‡è®°\ ``[E1,E2,E3,...,En|Variable]``\ ,其ä¸\ ``n`` |>=| ``1``\ ,用于表示å‰\ ``n``\ ä¸ªå…ƒç´ ä¸º\ ``E1,E2,E3,...,En``\ 其余部分由\ ``Variable``\ 指代的列表。当\ ``n = 1``\ 时,列表的形å¼ä¸º\ ``[H|T]``\ ;这个形å¼çš„出现频率éžå¸¸é«˜ï¼Œé€šå¸¸å°†\ ``H``\ 称为列表的\ **头部**\ ,而\ ``T``\ 为列表的\ **尾部**\ 。 æœ¬ç« æˆ‘ä»¬å°†è®¨è®ºå¦‚ä½•å¤„ç†\ **真**\ 列表;å³å°¾éƒ¨ä¸ºç©ºåˆ—表\ ``[]``\ 的列表。 应该记ä½åœ¨å¤„ç†\ **固定数目**\ çš„å…ƒç´ æ—¶æ€»æ˜¯åº”è¯¥ä½¿ç”¨å…ƒç»„\ ``tuple``\ 。元组所å çš„å˜å‚¨ç©ºé—´ä»…是列表的一åŠå¹¶ä¸”访问也更迅速。在需è¦å¤„ç†å¯å˜æ•°ç›®ä¸ªå…ƒç´ æ—¶æ‰åº”该使用列表。 用于列表处ç†çš„BIF ================= 一些内置函数å¯ç”¨äºŽåˆ—表与其他数æ®ç±»åž‹é—´çš„互相转æ¢ã€‚主è¦çš„BIF包括: ``atom_to_list(A)`` 将原åå¼\ ``A``\ 转æ¢ä¸ºä¸€ä¸ªASCIIå—符列表。 如:\ ``atom_to_list(hello)``\ |=>|\ ``[104,101,108,108,111]``\ [#]_\ 。 ``float_to_list(F)`` 将浮点数\ ``F``\ 转æ¢ä¸ºä¸€ä¸ªASCIIå—符列表。 如:\ ``float_to_list(1.5)``\ |=>|\ ``[49,46,53,48,48,...,48]``\ 。 ``integer_to_list(I)`` 将整数\ ``I``\ 转æ¢ä¸ºä¸€ä¸ªASCIIå—符列表。 如:\ ``integer_to_list(1245)``\ |=>|\ ``[[49,50,52,53]``\ 。 ``list_to_atom(L)`` å°†ASCIIå—符列表\ ``L``\ 转æ¢ä¸ºä¸€ä¸ªåŽŸåå¼ã€‚ 如:\ ``list_to_atom([119,111,114,108,100])``\ |=>|\ ``world``\ 。 ``list_to_float(L)`` å°†ASCIIå—符列表\ ``L``\ 转æ¢ä¸ºä¸€ä¸ªæµ®ç‚¹æ•°ã€‚ 如:\ ``list_to_float([51,46,49,52,49,53,57])``\ |=>|\ ``3.14159``\ 。 ``list_to_integer(L)`` å°†ASCIIå—符列表\ ``L``\ 转æ¢ä¸ºä¸€ä¸ªæ•´æ•°ã€‚ 如:\ ``list_to_integer([49,50,51,52])``\ |=>|\ ``1234``\ 。 ``hd(L)`` 返回列表\ ``L``\ çš„ç¬¬ä¸€ä¸ªå…ƒç´ ã€‚ 如:\ ``hd([a,b,c,d])``\ |=>|\ ``a``\ 。 ``tl(L)`` 返回列表\ ``L``\ 的尾部。 如:\ ``tl([a,b,c,d])``\ |=>|\ ``[b,c,d]``\ 。 ``length(L)`` 返回列表\ ``L``\ 的长度。 如:\ ``length([a,b,c,d])``\ |=>|\ ``4``\ 。 有两个BIF ``tuple_to_list/1``\ å’Œ\ ``list_to_tuple/1``\ 将放在第??ç« è®¨è®ºã€‚è¿˜æœ‰ä¸€äº›åˆ—è¡¨å¤„ç†ç›¸å…³çš„BIF,如\ ``list_to_pid(AsciiList)``\ ã€\ ``pid_to_list(Pid)``\ 。这些将在附录Bä¸æ述。 常用列表处ç†å‡½æ•° ================ 以下å„å°èŠ‚给出了一些简å•åˆ—表处ç†å‡½æ•°çš„使用示例。这里所æ述的所有函数都包å«åœ¨æ ‡å‡†Erlangå‘行版的\ ``lists``\ 模å—ä¸ï¼ˆç»†èŠ‚å‚è§é™„录C)。 ``member`` ---------- ``member(X, L)``\ 在\ ``X``\ 是列表\ ``L``\ çš„å…ƒç´ æ—¶è¿”å›ž\ ``true``\ ,å¦åˆ™è¿”回\ ``false``\ 。 .. code-block:: erlang member(X, [X|_]) -> true; member(X, [_|T]) -> member(X, T); member(X, []) -> false. ``member``\ 的第一个åå¥åŒ¹é…的是\ ``X``\ ä¸ºåˆ—è¡¨çš„ç¬¬ä¸€ä¸ªå…ƒç´ çš„æƒ…å†µï¼Œè¿™ç§æƒ…况下\ ``member``\ 返回\ ``true``\ 。如果第一个åå¥ä¸åŒ¹é…,则第二个åå¥å°†åŒ¹é…第二个å‚数是éžç©ºåˆ—表的情况,这ç§æƒ…况下模å¼\ ``[_|T]``\ 匹é…一个éžç©ºåˆ—表并将\ ``T``\ 绑定到列表的尾部,然åŽä»¥åŽŸæ¥çš„\ ``X``\ åŠåˆ—表的尾部\ ``T``\ 递归调用\ ``member``\ 。\ ``member``\ å‰ä¸¤ä¸ªåå¥å°±æ˜¯åœ¨è¯´å½“\ ``X``\ 是列表的\ **第一个**\ å…ƒç´ ï¼ˆå¤´éƒ¨ï¼‰ï¼Œæˆ–å®ƒè¢«åŒ…å«åœ¨åˆ—表的剩余部分(尾部)ä¸æ—¶ï¼Œ\ ``X``\ 就是该列表的一个æˆå‘˜ã€‚\ ``member``\ 的第三个åå¥æ˜¯è¯´\ ``X``\ ä¸å¯èƒ½æ˜¯ç©ºåˆ—表\ ``[]``\ çš„æˆå‘˜ï¼Œå¹¶å› æ¤è¿”回\ ``false``\ 。 我们将\ ``member``\ 的求值过程列举如下: .. code-block:: erlang > lists:member(a,[1,2,a,b,c]). (0)lists:member(a,[1,2,a,b,c]) (1).lists:member(a, [2,a,b,c]) (2)..lists:member(a,[a,b,c]) (2)..true (1).true (0)true true > lists:member(a,[1,2,3,4]). (0)lists:member(a, [1,2,3,4]) (1).lists:member(a, [2,3,4]) (2)..lists:member(a, [3,4]) (3)...lists:member(a, [4]) (4)....lists:member(a, []) (4)....false (3)...false (2)..false (1).false (0)false false ``append`` ---------- ``append(A,B)``\ 连接两个列表\ ``A``\ å’Œ\ ``B``\ 。 .. code-block:: erlang append([H|L1], L2) -> [H|append(L1, L2)]; append([], L) -> L. ``append``\ 的第二个åå¥å†æ˜Žç™½ä¸è¿‡äº†â€”—将任æ„列表\ ``L``\ è¿½åŠ è‡³ç©ºåˆ—è¡¨ä¹‹åŽä»å¾—到\ ``L``\ 。 第一个åå¥ç»™å‡ºäº†è¿½åŠ 一个éžç©ºåˆ—表到å¦ä¸€ä¸ªåˆ—表之åŽçš„è§„åˆ™ã€‚å› æ¤ï¼Œå¯¹äºŽï¼š .. code-block:: erlang append([a,b,c], [d,e,f]) 其求值结果为: .. code-block:: erlang [a | append([b,c], [d,e,f])] 那么\ ``append([b,c], [d,e,f])``\ 的值åˆæ˜¯å¤šå°‘呢?它(当然)是\ ``[b,c,d,e,f]``\ ï¼Œå› æ¤\ ``[a | append([b,c], [d,e,f])]``\ 的值就是\ ``[a|append([b,c], [d,e,f])]``\ ,这也是\ ``[a,b,c,d,e,f]``\ çš„å¦ä¸€ç§å†™æ³•ã€‚ ``append``\ 的行为如下: .. code-block:: erlang > lists:append([a,b,c],[d,e,f]). (0)lists:append([a,b,c],[d,e,f]) (1).lists:append([b,c], [d,e,f]) (2)..lists:append([c],[d,e,f]) (3)...lists:append([], [d,e,f]) (3)...[d,e,f] (2)..[c,d,e,f] (1).[b,c,d,e,f] (0)[a,b,c,d,e,f] [a,b,c,d,e,f] ``reverse`` ----------- ``reverse(L)``\ ç”¨äºŽé¢ å€’åˆ—è¡¨\ ``L``\ ä¸çš„å…ƒç´ é¡ºåºã€‚ .. code-block:: erlang reverse(L) -> reverse(L, []). reverse([H|T], Acc) -> reverse(T, [H|Acc]); reverse([], Acc) -> Acc. ``reverse(L)``\ 利用一个\ **辅助**\ 函数\ ``reverse/2``\ 将最终结果累积到第二个å‚æ•°ä¸ã€‚ 调用\ ``reverse(L, Acc)``\ 时,若\ ``L``\ 是一个éžç©ºåˆ—表,则将\ ``L``\ çš„ç¬¬ä¸€ä¸ªå…ƒç´ ç§»é™¤å¹¶\ **æ·»åŠ **\ 到\ ``Acc``\ çš„å¤´éƒ¨ã€‚å› æ¤å¯¹\ ``reverse([x,y,z], Acc)``\ 的调用将导致\ ``reverse([y,z], [x|Acc])``\ 的调用。最终\ ``reverse/2``\ 的第一个å‚数将归结为一个空列表,这时\ ``reverse/2``\ 的第二个åå¥å°†è¢«åŒ¹é…并å¦å‡½æ•°ç»“æŸã€‚ 整个过程如下: .. code-block:: erlang > lists:reverse([a,b,c,d]). (0)lists:reverse([a,b,c,d]) (1).lists:reverse([a,b,c,d], []) (2)..lists:reverse([b,c,d], [a]) (3)...lists:reverse([c,d], [b,a]) (4)....lists:reverse([d], [c,b,a]) (5).....lists:reverse([], [d,c,b,a]) (5).....[d,c,b,a] (4)....[d,c,b,a] (3)...[d,c,b,a] (2)..[d,c,b,a] (1).[d,c,b,a] (0)[d,c,b,a] [d,c,b,a] ``delete_all`` -------------- ``delete_all(X, L)``\ ç”¨äºŽåˆ é™¤åˆ—è¡¨\ ``L``\ ä¸å‡ºçŽ°çš„所有\ ``X``\ 。 .. code-block:: erlang delete_all(X, [X|T]) -> delete_all(X, T); delete_all(X, [Y|T]) -> [Y | delete_all(X, T)]; delete_all(_, []) -> []. ``delete_all``\ 所使用的递归模å¼ä¸Ž\ ``member``\ å’Œ\ ``append``\ 类似。 ``delete_all``\ 的第一个åå¥åœ¨è¦åˆ é™¤çš„å…ƒç´ å‡ºçŽ°åœ¨åˆ—è¡¨çš„å¤´éƒ¨æ—¶åŒ¹é…。 示例 ==== åœ¨ä»¥ä¸‹ç« èŠ‚ä¸æˆ‘们将给出一些ç¨å¾®å¤æ‚一些的列表处ç†å‡½æ•°çš„使用示例。 ``sort`` -------- 程åº3.1是著å的快速排åºçš„一个å˜ä½“。\ ``sort(X)``\ 对列表\ ``X``\ çš„å…ƒç´ æŽ’åºï¼Œå°†ç»“果放入一个新列表并将之返回。 .. topic:: 程åº3.1 .. code-block:: erlang -module(sort). -export([sort/1]). sort([]) -> []; sort([Pivot|Rest]) -> {Smaller, Bigger} = split(Pivot, Rest), lists:append(sort(Smaller), [Pivot|sort(Bigger)]). split(Pivot, L) -> split(Pivot, L, [], []). split(Pivot, [], Smaller, Bigger) -> {Smaller,Bigger}; split(Pivot, [H|T], Smaller, Bigger) when H < Pivot -> split(Pivot, T, [H|Smaller], Bigger); split(Pivot, [H|T], Smaller, Bigger) when H >= Pivot -> split(Pivot, T, Smaller, [H|Bigger]). æ¤å¤„选å–åˆ—è¡¨çš„ç¬¬ä¸€ä¸ªå…ƒç´ ä¸ºä¸è½´ã€‚元列表被分为两个列表\ ``Smaller``\ å’Œ\ ``Bigger``\ :\ ``Smaller``\ çš„æ‰€æœ‰å…ƒç´ éƒ½å°äºŽä¸è½´\ ``Pivot``\ 而\ ``Bigger``\ çš„æ‰€æœ‰å…ƒç´ éƒ½å¤§äºŽç‰äºŽ\ ``Pivot``\ 。之åŽï¼Œå†å¯¹åˆ—表\ ``Smaller``\ å’Œ\ ``Bigger``\ 分别排åºå¹¶å°†ç»“æžœåˆå¹¶ã€‚ 函数\ ``split({Pivot, L})``\ 返回元组\ ``{Smaller, Bigger}``\ ,其ä¸æ‰€æœ‰\ ``Bigger``\ ä¸çš„å…ƒç´ éƒ½å¤§äºŽç‰äºŽ\ ``Pivot``\ 而所有\ ``Smaller``\ ä¸çš„å…ƒç´ éƒ½å°äºŽ\ ``Pivot``\ 。\ ``split(Pivot, L)``\ 通过调用一个辅助函数\ ``split(Pivot, L, Smaller, Bigger)``\ 完æˆä»»åŠ¡ã€‚ä¸¤ä¸ªç´¯åŠ åˆ—è¡¨ï¼Œ\ ``Smaller``\ å’Œ\ ``Bigger``\ 分别用于å˜å‚¨\ ``L``\ ä¸å°äºŽå’Œå¤§äºŽç‰äºŽ\ ``Pivot``\ çš„å…ƒç´ ã€‚\ ``split/4``\ 的代ç 与\ ``reverse/2``\ éžå¸¸ç›¸åƒï¼Œåªæ˜¯å¤šç”¨äº†ä¸€ä¸ªç´¯åŠ 列表。例如: .. code-block:: erlang > lists:split(7,[2,1,4,23,6,8,43,9,3]). {[3,6,4,1,2],[9,43,8,23]} 如果我们调用\ ``sort([7,2,1,4,23,6,8,43,9,3])``\ ,首先就会以\ ``7``\ 为ä¸è½´æ¥è°ƒç”¨\ ``split/2``\ ã€‚è¿™å°†äº§ç”Ÿä¸¤ä¸ªåˆ—è¡¨ï¼šæ‰€æœ‰å…ƒç´ éƒ½å°äºŽä¸è½´\ ``7``\ çš„\ ``[3,6,4,1,2]``\ ,以åŠæ‰€æœ‰å…ƒç´ 都大于ç‰äºŽä¸è½´çš„\ ``[9,43,8,23]``\ 。 å‡è®¾\ ``sort``\ 工作æ£å¸¸ï¼Œåˆ™\ ``sort([3,6,4,1,2])``\ |=>|\ ``[1,2,3,4,6]``\ 而\ ``sort([9,43,8,23])``\ |=>|\ ``[8,9,23,43]``\ 。最åŽï¼ŒæŽ’好åºçš„列表被拼装在一起: .. code-block:: erlang > append([1,2,3,4,6], [7 | [8,9,23,43]]). [1,2,3,4,6,7,8,9,23,43] å†åŠ¨ä¸€ç‚¹è„‘ç‹ï¼Œéƒ½\ ``append``\ 的调用也å¯ä»¥çœæŽ‰ï¼Œå¦‚下所示: .. code-block:: erlang qsort(X) -> qsort(X, []). %% qsort(A,B) %% Inputs: %% A = unsorted List %% B = sorted list where all elements in B %% are greater than any element in A %% Returns %% sort(A) appended to B qsort([Pivot|Rest], Tail) -> {Smaller,Bigger} = split(Pivot, Rest), qsort(Smaller, [Pivot|qsort(Bigger,Tail)]); qsort([], Tail) -> Tail. 我们å¯ä»¥åˆ©ç”¨BIF\ ``statistics/1``\ (用于æ供系统性能相关的信æ¯ï¼Œå‚è§é™„录??)将之与第一版的\ ``sort``\ åšä¸€ä¸ªå¯¹æ¯”。如果我们编译并执行以下代ç 片段: .. code-block:: erlang ... statistics(reductions), lists:sort([2,1,4,23,6,7,8,43,9,4,7]), {_, Reductions1} = statistics(reductions), lists:qsort([2,1,4,23,6,7,8,43,9,4,7]), {_, Reductions2} = statistics(reductions), ... 我们å¯ä»¥å¾—知\ ``sort``\ å’Œ\ ``qsort``\ 的归约(函数调用)次数。在我们的示例ä¸\ ``sort``\ 花费\ ``93``\ 次归约,而\ ``qsort``\ 花费\ ``74``\ 次,æå‡äº†ç™¾åˆ†ä¹‹äºŒå。 é›†åˆ ---- 程åº3.2是一组简å•çš„集åˆæ“作函数。在Erlangä¸è¡¨ç¤ºé›†åˆçš„最直白的方法就是采用一个ä¸åŒ…å«é‡å¤å…ƒç´ çš„æ— åºåˆ—表。 集åˆæ“作函数如下: ``new()`` 返回一个空集åˆã€‚ ``add_element(X, S)`` è¿”å›žå°†å…ƒç´ \ ``X``\ 并入集åˆ\ ``S`` 产生的新集åˆã€‚ ``del_element(X, S)`` 返回从集åˆ\ ``S``\ ä¸åˆ åŽ»å…ƒç´ \ ``X``\ 的新集åˆã€‚ ``is_element(X, S)`` å½“å…ƒç´ \ ``X``\ 在集åˆ\ ``S``\ ä¸æ—¶è¿”回\ ``true``\ ,å¦åˆ™è¿”回\ ``false``\ 。 ``is_empty(S)`` 当集åˆ\ ``S``\ 为空集时返回\ ``true``\ ,å¦åˆ™è¿”回\ ``false``\ 。 ``union(S1, S2)`` 返回集åˆ\ ``S1``\ å’Œ\ ``S2``\ 的并集,å³åŒ…å«äº†\ ``S1``\ 或\ ``S2``\ æ‰€æœ‰å…ƒç´ çš„é›†åˆã€‚ ``intersection(S1, S2)`` 返回集åˆ\ ``S1``\ å’Œ\ ``S2``\ 的交集,å³ä»…包å«æ—¢åŒ…å«äºŽ\ ``S1``\ åˆåŒ…å«äºŽ\ ``S2``\ çš„å…ƒç´ çš„é›†åˆã€‚ ä¸¥æ ¼åœ°è¯´ï¼Œæˆ‘ä»¬å¹¶ä¸èƒ½è¯´\ ``new``\ 返回了一个空集,而应该说\ ``new``\ 返回了一个空集的\ **表示**\ 。如果我们将集åˆè¡¨ç¤ºä¸ºåˆ—表,则以上的集åˆæ“作å¯ä»¥ç¼–写如下: .. topic:: 程åº3.2 .. code-block:: erlang -module(sets). -export([new/0, add_element/2, del_element/2, is_element/2, is_empty/1, union/2, intersection/2]). new() -> []. add_element(X, Set) -> case is_element(X, Set) of true -> Set; false -> [X|Set] end. del_element(X, [X|T]) -> T; del_element(X, [Y|T]) -> [Y|del_element(X,T)]; del_element(_, []) -> []. is_element(H, [H|_]) -> true; is_element(H, [_|Set]) -> is_element(H, Set); is_element(_, []) -> false. is_empty([]) -> true; is_empty(_) -> false. union([H|T], Set) -> union(T, add_element(H, Set)); union([], Set) -> Set. intersection(S1, S2) -> intersection(S1, S2, []). intersection([], _, S) -> S; intersection([H|T], S1, S) -> case is_element(H,S1) of true -> intersection(T, S1, [H|S]); false -> intersection(T, S1, S) end. è¿è¡Œç¨‹åº3.2的代ç : .. code-block:: erlang > S1 = sets:new(). [] > S2 = sets:add_element(a, S1). [a] > S3 = sets:add_element(b, S2). [b,a] > sets:is_element(a, S3). true > sets:is_element(1, S2). false > T1 = sets:new(). [] > T2 = sets:add_element(a, T1). [a] > T3 = sets:add_element(x, T2). [x,a] > sets:intersection(S3, T3). [a] 10> sets:union(S3,T3). [b,x,a] 这个实现并ä¸å分高效,但足够简å•ä»¥ä¿è¯å…¶æ£ç¡®æ€§ï¼ˆä½†æ„¿å¦‚æ¤ï¼‰ã€‚今åŽè¿˜å¯ä»¥å°†ä¹‹æ›¿æ¢ä¸ºä¸€å¥—更高效的实现。 ç´ æ•° ---- 在我们的最åŽä¸€ä¸ªä¾‹å(程åº3.3)ä¸ï¼Œæˆ‘们将æ¥çœ‹çœ‹å¦‚何使用\ **埃拉托色尼ç›æ³•**\ æ¥ç”Ÿæˆä¸€å¼ ç´ æ•°è¡¨ã€‚ .. topic:: ç¨‹åº 3.3 .. code-block:: erlang -module(siv). -compile(export_all). range(N, N) -> [N]; range(Min, Max) -> [Min | range(Min+1, Max)]. remove_multiples(N, [H|T]) when H rem N == 0 -> remove_multiples(N, T); remove_multiples(N, [H|T]) -> [H | remove_multiples(N, T)]; remove_multiples(_, []) -> []. sieve([H|T]) -> [H | sieve(remove_multiples(H, T))]; sieve([]) -> []. primes(Max) -> sieve(range(2, Max)). 注æ„在程åº3.3ä¸æˆ‘ä»¬ä½¿ç”¨äº†ç¼–è¯‘å™¨æ ‡æ³¨\ ``-compile(export_all)``\ ——这将éšå¼åœ°å¯¼å‡ºè¯¥æ¨¡å—ä¸çš„æ‰€æœ‰å‡½æ•°ï¼ŒäºŽæ˜¯æˆ‘ä»¬æ— é¡»æ˜¾å¼åœ°ç»™å‡ºå¯¼å‡ºç”³æ˜Žä¾¿å¯ä»¥è°ƒç”¨è¿™äº›å‡½æ•°ã€‚ ``range(Min, Max)``\ 返回一个包å«ä»Ž\ ``Min``\ 到\ ``Max``\ 的所有整数的列表。 ``remove_multiples(N, L)``\ 从列表\ ``L``\ åˆ é™¤ä¸\ ``N``\ çš„å€æ•°ï¼š .. code-block:: erlang > siv:range(1,15). [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] > siv:remove_multiples(3,[1,2,3,4,5,6,7,8,9,10]). [1,2,4,5,7,8,10] ``sieve(L)``\ ä¿ç•™åˆ—表\ ``L``\ 的头部,对于尾部的列表,则å†é€’å½’åœ°åˆ é™¤å…¶å¤´éƒ¨çš„æ‰€æœ‰å€æ•°ï¼š .. code-block:: erlang > siv:primes(25). [2,3,5,7,11,13,17,19,23] åˆ—è¡¨çš„å¸¸ç”¨é€’å½’æ¨¡å¼ ================== 尽管一个典型的程åºå¾€å¾€ä¼šä½¿ç”¨å¾ˆå¤šä¸åŒçš„函数æ¥æ“作列表,但大多数列表处ç†å‡½æ•°éƒ½æ˜¯ç”±å°‘æ•°å‡ ç§æ¨¡å¼æ¼”å˜è€Œæ¥ã€‚大部分列表处ç†å‡½æ•°æ— éžå°±æ˜¯åœ¨å¹²ç€è¿™äº›äº‹æƒ…: - 在一个列表ä¸å¯»æ‰¾ä¸€ä¸ªå…ƒç´ ,并在找到时åšäº›äº‹æƒ…。 - 对输入列表的æ¯ä¸ªå…ƒç´ åšäº›äº‹æƒ…å¹¶æž„é€ ä¸€ä¸ªä¸Žå…¶ç»“æž„ç›¸åŒçš„输出列表。 - 在é‡åˆ°åˆ—表ä¸çš„第\ *n*\ ä¸ªå…ƒç´ æ—¶åšäº›äº‹æƒ…。 - 对列表进行扫æï¼Œå¹¶æž„é€ ä¸€ä¸ªæˆ–ä¸€ç»„ä¸ŽåŽŸåˆ—è¡¨ç›¸å…³çš„æ–°åˆ—è¡¨ã€‚ 我们将以æ¤å¯¹å…¶è¿›è¡Œè®¨è®ºã€‚ æœç´¢åˆ—è¡¨å…ƒç´ ------------ 给定以下递归模å¼ï¼š .. code-block:: erlang search(X, [X|T]) -> ... do something ... ...; search(X, [_|T]) -> search(X, T); search(X, []) -> ... didn't find it ... 第一ç§æƒ…况匹é…的是找到了我们所感兴趣的项的情形。第二ç§æƒ…况在列表的头部ä¸æ˜¯æˆ‘们所感兴趣的项时匹é…,这时将接ç€å¤„ç†åˆ—表的尾部。最åŽä¸€ç§æƒ…况匹é…çš„æ˜¯åˆ—è¡¨å…ƒç´ è€—å°½çš„æƒ…å½¢ã€‚ 将以上代ç 与\ ``member/2``\ 的代ç (第??节)作个比较,我们å¯ä»¥çœ‹åˆ°æˆ‘们ä¸è¿‡æ˜¯æŠŠ\ ``... do something ...``\ æ¢æˆäº†\ ``true``\ ,把\ ``... didn't find it ...``\ æ¢æˆäº†\ ``false``\ 。 构建åŒæž„列表 ------------ æœ‰æ—¶æˆ‘ä»¬ä¼šæƒ³æž„é€ ä¸€ä¸ª\ **形如**\ 输入列表的列表,但åŒæ—¶åˆè¦å¯¹è¾“入列表的æ¯ä¸ªå…ƒç´ åšäº›æ“作。这时å¯ä»¥è¿™ä¹ˆå†™ï¼š .. code-block:: erlang isomorphic([X|T]) -> [something(X)|isomorphic(T)]; isomorphic([]) -> []. 然åŽï¼Œæ¯”如我们想写一个将给定列表ä¸çš„æ‰€æœ‰å…ƒç´ ç¿»å€çš„函数,我们就å¯ä»¥è¿™ä¹ˆå†™ï¼š .. code-block:: erlang double([H|T]) -> [2 * H | double(T)]; double([]) -> []. 于是便有: .. code-block:: erlang > lists1:double([1,7,3,9,12]). [2,14,6,18,24] 事实上这ç§æ‰‹æ³•åªèƒ½ä½œç”¨äºŽåˆ—表的\ **最上层**\ ï¼Œå› æ¤å¦‚果我们想é历列表的所有层次,我们就得将函数定义修改如下: .. code-block:: erlang double([H|T]) when integer(H)-> [2 * H | double(T)]; double([H|T]) when list(H) -> [double(H) | double(T)]; double([]) -> []. åŽä¸€ä¸ªç‰ˆæœ¬å°±å¯ä»¥æˆåŠŸé历深层的嵌套列表了: .. code-block:: erlang > lists1:double([1,2,[3,4],[5,[6,12],3]]). [2,4,[6,8],[10,[12,24],6]] 计数 ---- 我们常常è¦ä½¿ç”¨åˆ°è®¡æ•°å™¨ï¼Œä»¥ä¾¿å¯¹ä¸€ä¸ªåˆ—表的第\ *n*\ ä¸ªå…ƒç´ åšäº›åŠ¨ä½œï¼š .. code-block:: erlang count(Terminal, L) -> ... do something ...; count(N, [_|L]) -> count(N-1, L). 则返回列表ä¸ç¬¬\ *n*\ ä¸ªå…ƒç´ ï¼ˆå‡è®¾å…¶å˜åœ¨ï¼‰çš„函数å¯ä»¥å†™æˆï¼š .. code-block:: erlang nth(1, [H|T]) -> H; nth(N, [_|T]) -> nth(N - 1, T). è¿™ç§é€’å‡è‡³ä¸€ä¸ªç»ˆæ¢æ¡ä»¶çš„计数方å¼å¾€å¾€è¦ç”±äºŽé€’增计数。为了说明这一点,考虑åŒæ ·æ˜¯è¿”回第\ *n*\ ä¸ªå…ƒç´ ä½†æ˜¯é‡‡ç”¨é€’å¢žè®¡æ•°çš„å‡½æ•°\ ``nth1``\ : .. code-block:: erlang nth1(N, L) -> nth1(1, N, L). nth1(Max, Max, [H|_]) -> H; nth1(N, Max, [_|T]) -> nth1(N+1, Max, T). è¿™ç§åšæ³•éœ€è¦ä¸€ä¸ªé¢å¤–çš„å‚数和一个辅助函数。 æ”¶é›†åˆ—è¡¨å…ƒç´ ------------ 现在我们希望对一个列表ä¸çš„å…ƒç´ åšäº›åŠ¨ä½œï¼Œç”Ÿæˆä¸€ä¸ªæˆ–一组新的列表。对应的模å¼å¦‚下: .. code-block:: erlang collect(L) -> collect(L, []). collect([H|T], Accumulator) -> case pred(H) of true -> collect(T, [dosomething(H)|Accumulator]); false -> collect(T, Accumulator) end; collect([], Accumulator) -> Accumulator. 在这里我们引入了一个多出一个å‚数的辅助函数,多出的这个å‚数用于å˜å‚¨æœ€ç»ˆè¦è¢«è¿”回给调用方的列表。 å€ŸåŠ©è¿™æ ·ä¸€ç§æ¨¡å¼ï¼Œä¸¾ä¸ªä¾‹å,我们å¯ä»¥å†™è¿™æ ·çš„一个函数:计算输入列表的所有å¶å…ƒç´ çš„å¹³æ–¹å¹¶åˆ é™¤æ‰€æœ‰å¥‡å…ƒç´ ï¼š .. code-block:: erlang funny(L) -> funny(L, []). funny([H|T], Accumulator) -> case even(H) of true -> funny(T, [H*H|Accumulator]); false -> funny(T, Accumulator) end; funny([], Accumulator) -> Accumulator. 于是有: .. code-block:: erlang > lists:funny([1,2,3,4,5,6]) [36,16,4] 注æ„在这ç§æƒ…况下结果列表ä¸çš„å…ƒç´ çš„é¡ºåºä¸ŽåŽŸåˆ—表ä¸å¯¹åº”å…ƒç´ çš„é¡ºåºæ˜¯ç›¸å的。 在递归过程ä¸ä½¿ç”¨ç´¯åŠ 列表æ¥æž„é€ ç»“æžœç»å¸¸æ˜¯ä¸€ç§æŽ¨èçš„åšæ³•ã€‚è¿™æ ·å¯ä»¥ç¼–写出è¿è¡Œæ—¶åªé€‚用常数空间的\ **æ‰å¹³**\ 的代ç (细节å‚è§ç¬¬??节)。 函数å¼å‚æ•° ========== 将函数å作为å‚æ•°ä¼ é€’ç»™å¦ä¸€ä¸ªå‡½æ•°æ˜¯ä¸€ç§å¾ˆæœ‰ç”¨çš„抽象特定函数行为的方法。本节将给出两个使用这ç§ç¼–程技术的示例。 map --- 函数\ ``map(Func, List)``\ 返回一个列表\ ``L``\ ,其ä¸çš„å…ƒç´ ç”±å‡½æ•°\ ``Func``\ ä¾æ¬¡ä½œç”¨äºŽåˆ—表\ ``List``\ çš„å„ä¸ªå…ƒç´ å¾—åˆ°ã€‚ .. code-block:: erlang map(Func, [H|T]) -> [apply(F, [H])|map(Func, T)]; map(Func, []) -> []. > lists:map({math,factorial}, [1,2,3,4,5,6,7,8]). [1,2,6,24,120,720,5040,40320] filter ------ 函数\ ``filter(Pred, List)``\ 对列表\ ``List``\ ä¸çš„å…ƒç´ è¿›è¡Œè¿‡æ»¤ï¼Œä»…ä¿ç•™ä»¤\ ``Pred``\ 的值为\ ``true``\ çš„å…ƒç´ ã€‚è¿™é‡Œçš„\ ``Pred``\ 是一个返回\ ``true``\ 或\ ``false``\ 的函数。 .. code-block:: erlang filter(Pred, [H|T]) -> case apply(Pred,[H]) of true -> [H|filter(Pred, T)]; false -> filter(Pred, T) end; filter(Pred, []) -> []. å‡è®¾å‡½æ•°\ ``math:even/1``\ 在å‚数为å¶æ•°æ—¶è¿”回\ ``true``\ ,å¦åˆ™è¿”回\ ``fale``\ ,则: .. code-block:: erlang > lists:filter({math,even}, [1,2,3,4,5,6,7,8,9,10]). [2,4,6,8,10] .. rubric:: 脚注 .. [#] æ ‡è®°\ ``Lhs``\ |=>|\ ``Rhs``\ 代表对\ ``Lhs``\ 求值的结果为\ ``Rhs``\ 。 .. vim:ft=rst ts=4 sw=4 fenc=utf-8 enc=utf-8 et