:【原訳】Efficiency Gide Elangリスト処理

8144 ワード

回転:http://www.cnblogs.com/futuredo/archive/2012/10/22/2734186.html
 
List handling
1  Creating a list
リストを作成
Lists can only be built starting from the end and ataching list elemens at the beginning.If you use the ++ operator like this
リストは、端からのみ作成できます。頭から要素を追加します。このように+操作子を使うと
 
List1 ++ List2
 
you will create a new list which is copy of the elements in List 1、フォローアップby List 2.Looking at how lists:apped/1 or ++would be implemened in Elang、it can be seen clearly that the first list is copied:
リストを作成します。このリストはList 1のコピーとList 2です。listsを見てください。apped/1関数または+オペレータはErrlangの中でどのように実現されていますか?最初のリストがコピーされていることが分かります。(%1%は入力リストの要素を取って、新しいリストに加えます。%
 
append([H|T], Tail) ->

    [H|append(T, Tail)];

append([], Tail) ->

    Tail.
 
So the importent thing when recursing and building a list is to make sure that You atch the new element to the beginning of the list,so that you build a. list、and not hndreds or thousands of copies of the growing reult list.
したがって、リストを再帰的に巡回して作成する際には、新しい要素をリストのヘッダに追加することで、リストのコピーを100以上作ることができなくなります。
Let us first look at how it shound not be done:
まず使ってはいけない方法を見てみましょう。
DO NOT
 
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]).
 
Here we are not a building a list;in each iteration step we create a new list that is one element longer than the new previous list.
ここではリストを作成していません。反復ごとに、私たちは新しいリストを作成しました。この新しいリストは前回作成したリストよりも多くの要素があります。
To avoid copying the result in each iteration、we must build the list in reverse order and reverse the list when were done:
反復ごとに最後の結果をコピーしないためには、リストを逆の順序で作成し、終了時にリストを反転させる必要があります。
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]).


 
2  List compone hensions
リスト解析
Lists coprehensions still have a reputation for being slow.The y used to be implement using funs,which used to be slow.
リスト解析はまだ効率が遅いと考えられています。それらは以前は関数を使って実現したが、関数は過去にも効率が遅い。
In recent Elang/OTP releases(including R 12 B)、a list compprehension
最近のErrlang/OTPバージョンでは(R 12 Bを含む)、リスト解析
 
[Expr(E) || E <- List]
 
is baically translated to a local function
ローカル関数に変換されます。
 
'lc^0'([E|Tail], Expr) ->

    [Expr(E)|'lc^0'(Tail, Expr)];

'lc^0'([], _Expr) -> [].
 
In R 12 B,if the result of the list compone will Oviously not be used、a list will not be constructed.For instance、in this code
R 12 Bバージョンでは、リスト解析の結果が、使用されないことが明確に示されていれば、リストは作成されません。例えば、次のコードには
 
[io:put_chars(E) || E <- List],

ok.
 
or in this code
または以下のコード
 
.

.

.

case Var of

    ... ->

        [io:put_chars(E) || E <- List];

    ... ->

end,

some_function(...),

.

.

.
 
the value is neither assigned to a variable、nor passed to another function、nor returned、so there isのneed to construct a list and the complify the code for the list corespection
リスト内の要素は変数に値を与えたり、他の関数に転送されたりしないので、リストを作成する必要はありません。コンパイラはリスト解析のコードを簡単に次の形式に簡略化します。
 
'lc^0'([E|Tail], Expr) ->

    Expr(E),

    'lc^0'(Tail, Expr);

'lc^0'([], _Expr) -> [].


 
3  Deep and flat lists
深さフラットリスト
lists:flaten/1 builds an entirely new list.The refore,it is expensive,and even メモリ expensive than the ++ (which copies its left argment、but not its right argment)
lists:flaten/1関数は完全に新しいリストを作成します。したがって、そのオーバーヘッドは非常に大きく、++操作子よりも大きい(+操作子はその左の値だけをコピーし、右の値はコピーしない)。
(%flatenの効果は、深さのリストを[[1]、[2]、[3]]のように[1,2,3]に変換し、元のリストのすべての要素をコピーします。
In the follwing situration s,you can easumily avoid caling lists:flaten/1:
  • When sending data to a port.Ports understand deep lists so there isのreason to flant the list before sending it to the port.
  • When caling BIFs that accept deep lists,such as リスト.to_binary/1 or オリスト.to_binary/1.
  • When you know that your list is only one level deep,you can can use lists:apped/1.
  • 以下のいくつかの場合、簡単にlistsを呼び出すことを避けることができます:flaten/1関数:
  • が一つのポートにデータを送信するとき。ポートは(%または%の解析が可能です)deep list(深リスト)を知っていますので、リストをポートに送る前にフラット化する必要はありません。
  • 呼び出しto_binary/1またはiolist_to_binary/1などのようなdeep lists(深リスト)の内蔵関数を受信する場合。
  • リストが1レベルの深さしかないことを知っている時、list:apped/1関数を使うことができます。(%1 one level deepは[[1],[2],[3]]のように、appnd関数を使って偏平化するべきです。 %%)
  • ポートexample
    ポートの例
    DO
     
          ...
    
          port_command(Port, DeepList)
    
          ...
     
    DO NOT
     
          ...
    
          port_command(Port, lists:flatten(DeepList))
    
          ...
     
    A common way to send a zro-terminated string to a port is the follwing:
    以下は一般的な(推奨されていない)0の終端文字列をポートに送信する方法です。
    (%2種類の付加元素の方式の対比は、最終結果の深さが異なる%)
    DO NOT
     
          ...
    
          TerminatedStr = String ++ [0], % String="foo" => [$f, $o, $o, 0]
    
          port_command(Port, TerminatedStr)
    
          ...
     
    Instead do like this:
    このようにするべきです。
    DO
     
          ...
    
          TerminatedStr = [String, 0], % String="foo" => [[$f, $o, $o], 0]
    
          port_command(Port, TerminatedStr) 
    
          ...
     
    Apped example
    サンプルを追加
    DO
     
          > lists:append([[1], [2], [3]]).
    
          [1,2,3]
    
          >
     
    DO NOT
     
          > lists:flatten([[1], [2], [3]]).
    
          [1,2,3]
    
          >


     
    4  Why you shound not worly about recursive lists functions
    再帰リスト関数の原因を心配する必要はありません。
    In the performance myschapter,the follwing mys was exposed: Tail-recursive functions are MUCH faster than recursive functions.
    性能の誤りの章では、この落とし穴について述べました。後戻り関数は通常の再帰関数よりも効率的です。
    Tosummarrize,in R 12 B there isusuualy not much difference between a bod- recursive list Fnction and tail-recursive function reverses the list the end.Threfore,concerate on on on writititititititititititititititititbeaaaaaaaaaaatttttttttttttttfffffffffffffflalalalalalaladededededeaaaaaaaaaaaaaaaaaaaaaaaattttttttttttttttttre), メスア before rewriting your code.
    まとめてみますと、R 12 Bバージョンでは、再帰関数と尾再帰関数は、同じように終了時にリストを反転させます。通常は大きな違いはありません。したがって、きれいなコードだけを書くことに集中して、リスト関数の性能を心配する必要はありません。時間性能が非常に重要な部分のコードだけは、書き換える前に見積りをしてください。
    Important note:This section talks about lists functions that construct lists.A tail-recursive function that does not construct a list runs in constant space,while the coreress ponding body-recursive function usce station space propotion the length of the list.For instance,a function stanction starst of the。 not be written like this
    ポイント:このセクションでは、リストを構成する関数について説明します。リストを作成しないと、末尾再帰関数は定数空間だけが必要です。逆に、再帰関数が占有するスタック空間はリストの長さに比例します。たとえば、整数リスト要素の総和を計算する関数は、このように書くべきではありません。
    DO NOT
     
    recursive_sum([H|T]) -> H+recursive_sum(T);
    
    recursive_sum([])    -> 0.
     
    but like this
    このようにすべきです
    DO
    sum(L) -> sum(L, 0). sum([H|T], Sum) -> sum(T, Sum + H); sum([], Sum) -> Sum.