無題の備忘録

IT技術について調べたことや学んだこと、試したこと記録するブログです。Erlang、ネットワーク、 セキュリティ、Linux関係のものが多いです。

Erlang の lists モジュールを一通り試す - その4

最近、Erlang のコードを読んでいて、lists:any という関数が出てきたのだが、知らなかったので調べた。ついでに、他の関数も一通り眺めておく。

公式URL: http://erlang.org/doc/man/lists.html

map/2 関数

map(Fun, List1) -> List2

Types

Fun = fun((A) -> B)
List1 = [A]
List2 = [B]
A = B = term()

リスト List1 のすべての要素に関数 Fun を適用して List2 を作成する。 この関数は、戻り値を得るために使用する。 評価順序は実装によって異なる。

> F = fun(X) -> atom_to_list(X) end.
#Fun<erl_eval.6.99386804>
> lists:map(F, [apple, banana, cherry]).
["apple","banana","cherry"]

戻り値を得るために使用するように記載があるため、関数 Fun が評価される順番は定義されていないようなので、リストの順番に依存する副作用がある関数を Fun に指定することは避けた方が良さそう。

リストの順番に副作用のある関数は、foreach/2 関数を使う。

mapfoldl/3 関数

mapfoldl(Fun, Acc0, List1) -> {List2, Acc1}

Types

Fun = fun((A, AccIn) -> {B, AccOut})
Acc0 = Acc1 = AccIn = AccOut = term()
List1 = [A]
List2 = [B]
A = B = term()

map/2 と foldl/3 を同時に実行する。Fun の戻り値は {B, AccOut} の形式である必要がある。Bは map/2 の Fun の戻り値のように扱われる。 AccOut は foldl/3 の Fun の戻り値のように扱われる。

> F = fun(X, Acc) -> {integer_to_list(X), X+Acc} end.
#Fun<erl_eval.12.99386804>
> lists:mapfoldl(F, 0, [1,2,3,4,5]).
{["1","2","3","4","5"],15}

上記の例では、map/2 として integer_to_list/1 を適用し、 foldl/2 としてリストの合計値を計算したもの。

mapfoldr/3 関数

mapfoldr(Fun, Acc0, List1) -> {List2, Acc1}

Types

Fun = fun((A, AccIn) -> {B, AccOut})
Acc0 = Acc1 = AccIn = AccOut = term()
List1 = [A]
List2 = [B]
A = B = term()

map/2 と foldr/3 を同時に実行する。

> F = fun(X, Acc) -> io:format("~p ", [X]), {integer_to_list(X), X+Acc} end.
#Fun<erl_eval.12.99386804>
> lists:mapfoldl(F, 0, [1,2,3,4,5]).                                        
1 2 3 4 5 {["1","2","3","4","5"],15}
> lists:mapfoldr(F, 0, [1,2,3,4,5]).
5 4 3 2 1 {["1","2","3","4","5"],15}

io:format/2 関数で X の値をプリントすると、mapfoldl/3 では関数 Fun の適用がリストの左からであることが、mapfoldr/3 では 関数 Fun の適用がリストの右からであることがわかる。

max/1 関数

max(List) -> Max

Types

List = [T, ...]
Max = T
T = term()

リスト内の要素同士を比較して、その最大値の要素を返す。

> lists:max([1,2,3,4,5]).
5
> lists:max([a,b,c,d,e]).
e
> lists:max([ax,bx,cx,dx,ex]).
ex
> lists:max(["ax","bx","cx","dx","ex"]).
"ex"
> lists:max([{a, "A"},{b,"B"},{c,"C"},{d, "D"},{e, "E"}]).
{e,"E"}
> lists:max([{a, "A", "AA"},{b,"B"},{c,"C"},{d, "D"},{e, "E"}]).
{a,"A","AA"}
>lists:max([{a, "A", "AA"},{b,"B"},{c,"C"},{d, "D"},5, e, [1,2,3,4,5]]).
[1,2,3,4,5]

一般的には、数値のリストで使うことが多いと思うが、要素は数値でなくても最大値を得ることができる。

Erlangの比較では、すべての term() について下記のように全順序が定義されている。

数 < アトム < リファレンス < fun < ポート < プロセスID < タプル < リスト < バイナリ

これは、どんな数でもアトムより小さく、どんなアトムでもタプルより小さいといった感じの意味だ。

member/2 関数

member(Elem, List) -> boolean()

Types

Elem = T
List = [T]
T = term()

Listの要素に Elem と一致するものがある場合は true、そうでない場合は false を返す。

> lists:member(a, [a,b,c,d,e]).
true
> lists:member(f, [a,b,c,d,e]).
false

merge/1 関数

merge(ListOfLists) -> List1

Types

ListOfLists = [List]
List = List1 = [T]
T = term()

ListOfLists のすべてのサブリストをマージして形成されたソート済みリストを返す。 この関数を評価する前に、すべてのサブリストをソートする必要がある。 2つの要素が等しい場合、ListOfLists で最も低い位置にあるサブリストの要素が他の要素の前に選択される。

> SubList1 = [a, b, c, d, e].
> SubList2 = [1, 2, a, b, c].
> SubList3 = [1, 2, 3, 4, 5].
> lists:merge([SubList1, SubList2, SubList3]).
[1,1,2,2,3,4,5,a,a,b,b,c,c,d,e]
SubList1 = [{apple,130},{cherry,160}].
SubList2 = [{apple,120},{banana,130},{strawberry,140}].
> lists:merge([SubList1, SubList2]).
[{apple,120},
 {apple,130},
 {banana,130},
 {cherry,160},
 {strawberry,140}]

下記のように SubList3 をわざとソートできていないリストにすると、下記のように merge/1 の結果もソートできていないリストが得られるので注意する。

> SubList1 = [a, b, c, d, e].                 
> SubList2 = [1, 2, a, b, c].                 
> SubList3 = [5, 4, 3, 2, 1].
> lists:merge([SubList1, SubList2, SubList3]).
[1,2,5,4,3,2,1,a,a,b,b,c,c,d,e]

merge/2 関数

merge(List1, List2) -> List3

Types

List1 = [X]
List2 = [Y]
List3 = [X | Y]
X = Y = term()

List1とList2をマージしてソートしたリストを返す。この関数を評価する前に、List1とList2の両方をソートする必要がある。 2つの要素が等しい場合、List1の要素がList2の要素の前に選択される。

> SubList1 = [a, b, c, d, e].
[a,b,c,d,e]
> SubList2 = [1, 2, a, b, c].
[1,2,a,b,c]
> lists:merge(SubList1, SubList2).
[1,2,a,a,b,b,c,c,d,e]

merge/3 関数

merge(Fun, List1, List2) -> List3

Types

Fun = fun((A, B) -> boolean())
List1 = [A]
List2 = [B]
List3 = [A | B]
A = B = term()

List1とList2をマージしてソートしたリストをす。 この関数を評価する前に、List1とList2の両方を順序付け関数 Fun に従ってソートする必要がある。 Fun(A, B) は、Aが順序でB以下である場合はtrueを返し、そうでない場合はfalseを返す関数を指定する。 2つの要素が等しい場合、List1の要素がList2の要素の前に選択される。

> F = fun(A, B) -> A >= B end.
#Fun<erl_eval.12.99386804>
> SubList1 = [d,c,a].
> SubList2 = [f,e,b].
> lists:merge(F, SubList1, SubList2).
[f,e,d,c,b,a]

「Aが順序でB以下である場合」というのは、「AをBよりもリストの左に置きたい場合」と読み替えると良い。

上の例では、Fun は A > B を評価しているので、AがBよりも大きい場合に true、そうでない場合は falseを返す。AがBより大きいとリストの左に置かれるので、降順に並べることができる。

merge3/3 関数

merge3(List1, List2, List3) -> List4

Types

List1 = [X]
List2 = [Y]
List3 = [Z]
List4 = [X | Y | Z]
X = Y = Z = term()

List1、List2、およびList3をマージしてソートしたリストを返す。 この関数を評価する前に、List1、List2、およびList3をすべてソートする必要がある。 2つの要素が等しい場合、そのような要素がある場合はList1の要素が他の要素の前に選択され、そうでない場合はList2の要素がList3の要素の前に選択される。

> SubList1 = [a, b, c, d, e].
> SubList2 = [1, 2, a, b, c].
> SubList3 = [1, 2, 3, 4, 5].
> lists:merge3(SubList1, SubList2, SubList3).
[1,1,2,2,3,4,5,a,a,b,b,c,c,d,e]