コレクション
■リスト
リストは複数個の値をまとめて扱うことができるデータ型です。
●リストの特性
Elixirのリストは連結リストになっています。
連結リストとは各要素が次の要素を持っているリストのことです。
なので、要素アクセスやサイズの取得処理が遅く、リストに要素を追加するのは
末尾ではなく、先頭に追加するほうが高速です。
●書式
・書式例
[値, 値, 値, ...]
・具体例
[1, 2, 3, 4, 5]
●複数の型
リストにまとめる値の型は複数の型を設定することが可能です。
・例
[1, :name, "yttm"]
●入れ子構造
リストの中にリストを設定する入れ子構造を作成することが可能です。
・例
[[1, 2], 3, [4, 5, 6]]
●参照
Elixirのリストの中の値はJavaやRubyなどのリスト名[インデックス番号]による方法では
参照することができません。
参照にはEnumモジュールのat関数を使用する必要があります。
・例
iex> list = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex> Enum.at(list, 4)
5
●変更
リストの値の変更はできません。
リストの値を別の値に変更したい場合、値を入れ替えた新しいリストを作成します。
Listモジュールのreplace_atを使用することで作成が可能です。
・例①(listは変わってない)
iex> list = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex> List.replace_at(list, 1, 1000)
[1, 1000, 3, 4, 5]
iex> list
[1, 2, 3, 4, 5]
・例②(リスト新規作成)
iex> list = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex> list2 = List.replace_at(list, 1, 1000)
[1, 1000, 3, 4, 5]
iex> list
[1, 2, 3, 4, 5]
iex> list2
[1, 1000, 3, 4, 5]
●追加
・cons演算子
先頭に要素を1つ追加する場合、「|」(cons演算子)を使用して連結することも可能です。
・例
iex> list = [1, 2]
[1, 2]
iex> [0 | list]
[0, 1, 2]
・cons演算子の注意点
cons演算子説明で「先頭に」と記述しているのは基本ルールで
右辺にはリストを指定しなければいけないということになっています。
リスト以外を指定しなくともエラーにはなりませんが、
「不適切リスト」と呼ばれる特殊リストが作成されます。
・不適切リスト例
iex> list = [1, 2]
[1, 2]
iex> list = [list | 3]
[[1, 2] | 3]
・末尾追加(リスト連結)
リストの末尾に要素を追加する場合は「++」演算子を使用します。
この演算子はリスト同士を連結することもできます。
・例
iex> list = [1, 2, 3]
[1, 2, 3]
iex> list = list ++ [4]
[1, 2, 3, 4]
iex> list2 = [5, 6, 7]
[5, 6, 7]
iex> list ++ list2
[1, 2, 3, 4, 5, 6, 7]
●減算
「--」演算子を使用することでリストから一部の値を削除して新しいリストを作成することができます。
・例
iex> list = [1, 2, 3, 4]
[1, 2, 3, 4]
iex list -- [1]
[2, 3, 4]
・指定した値が複数あった場合
減算する値がリストの中に複数あった場合は先頭から値を調べていき、
最初に見つかった要素を削除します。
・例
iex> list = [1, 2, 1, 2]
[1, 2, 1, 2]
iex> list -- [1]
[2, 1, 2]
・削除要素は順番不問
削除要素は対象リストの先頭から順番に判定していくので、削除リストの順番は関係ありません。
・例
iex> list = [1, 2, 3, 4]
[1, 2, 3, 4]
iex> list -- [4, 3, 2, 1]
[]
・存在しない要素の指定
削除リストの要素が対象リストの中になかった場合にエラーになることはありません。
・例
iex> list[1, 2, 3, 4]
[1, 2, 3, 4]
iex> list -- [4, 5, 6, 7]
[1, 2, 3]
●HeadとTail
リストでは先頭とそれ以外を取得する方法が用意されています。
・hd / tl
hdとtl関数を使用することで、リストの先頭とそれ以外の要素を取得できます。
・例
iex> list = [1, 2, 3, 4]
[1, 2, 3, 4]
iex> hd list
1
iex> tl list
[2, 3, 4]
■タプル
タプルも複数個の値をまとめて扱うことができるデータ型です。
●タプルの特性
タプルはリストとは違い、連続したメモリに値を保存するため、
インデックスによる要素へのアクセスや要素数の取得が高速です。
しかし、要素の追加や変更、削除などのタプルの操作処理は遅く、
要素数が大きいほど遅さが目立ちます。
また、リストで用意されている連結などの機能もタプルには用意されていません。
タプルは関数の戻り値やキーワードリストの要素などでよく利用されます。
●書式
・書式例
{ 値, 値, ... }
・具体例
{ 1, 2, 3 }
●複数の型
リストにまとめる値の型は複数の型を設定することが可能です。
・例
{ 1, :name, "yttm" }
●参照
タプルの要素へのアクセスはelemを使用します。
・例
iex> list = { 1, 2, 3 }
{1, 2, 3}
iex> elem(list, 1)
2
●変更
タプルも要素の変更はできません。
変更をする場合、値を変更した新しいタプルを作成する必要があります。
新しいタプルの作成はput_elemを使用しますが「●タプルの特性」で
説明しているとおり、タプルの要素の変更は処理コストが低くないので
使いすぎには注意して下さい。
・例(変更)
iex> list = { 1, 2, 3 }
{1, 2, 3}
iex> put_elem(list, 1, 100)
{1, 100, 3}
・例(新規タプル取得)
iex> list = { 1, 2, 3 }
{1, 2, 3}
iex> list2 = put_elem(list, 1, 100)
{1, 100, 3}
iex> list
{1, 2, 3}
iex> list2
{1, 100, 3}
■マップ
マップも複数個の値をまとめて扱うためのデータ型です。
各値にキーと呼ばれるユニークな値を設定し、そのキーに値を割り当てます。
●書式
・書式例
%{ キー => 値, キー => 値, ... }
・具体例
%{ "ID" => 1, "URL" => "yttm-work.jp" }
●キーの型
キーの型には文字列とアトムを使用することが一般的ですが、
整数など別の型を使用することも可能です。
・文字列例
%{ "ID" => 1, "URL" => "yttm-work.jp" }
・アトム
アトムのみ設定方法2種類あります。
・その1
%{ :ID => 1, :URL => "yttm-work.jp" }
・その2
%{ ID: 1, URL: "yttm-work.jp"}
・整数
%{ 1 => 1, 2 => "yttm-work.jp" }
・型混合
キーの型は統一されている必要はありません。
・例
%{ :ID => 1, "URL" => "yttm-work.jp", 3 => :tag }
アトムを使用する場合「アトム名:」の記述は使えないので注意して下さい。
・例
iex> %{ ID: 1, "URL" => "yttm-work"}
** (SyntaxError) iex:50: syntax error before: "URL"
●参照
・通常参照
マップの要素に参照は「変数名[キー]」で行うことができます。
・例
iex> list = %{ :ID => 1, "URL" => "yttm-work"}
%{ :ID => 1, "URL" => "yttm-work"}
iex> list[:ID]
1
iex> list["URL"]
"yttm-work.jp"
・アトムの特殊参照
アトムがキーとして使われており、アトムの文字が全て小文字の場合は
「変数名.キー」で参照可能です。
・例
iex> list = %{ :id => 1, :url => "yttm-work"}
%{ :id => 1, :url => "yttm-work"}
iex> list.url
"yttm-work.jp"
・キーなし
キーが存在しない場合はnilが返ります。
・例
iex> list = %{ :ID => 1, "URL" => "yttm-work"}
%{ :ID => 1, "URL" => "yttm-work"}
iex> list[:id]
nil
●値の変更
マップ内の値を変更はできません。
変更するには既存のマップを利用して、値を変更した新しいマップを作成する必要があります。
・例
iex> list = list = %{ "ID" => 1, "URL" => "yttm-work"}
%{ "ID" => 1, "URL" => "yttm-work"}
iex> list2 = %{ list | "ID" => 2 }
%{ "ID" => 2, "URL" => "yttm-work"}
●追加
マップに値して新しくキーを追加する場合、Map.marge関数を使用して
追加を行った新しいマップを作成します。
margeは値の追加だけではなく、値の変更も可能です。
・例
iex> list = %{ "ID" => 1, "URL" => "yttm-work.jp"}
%{ "ID" => 1, "URL" => "yttm-work"}
iex> list2 = Map.merge(list, %{"ID" => 2, "DESC" => "Look at everyone"})
%{"DESC" => "Look at everyone", "ID" => 2, "URL" => "yttm-work"}
●削除
・要素削除(1つ)
マップの要素を削除したい場合、Map.deleteを使用して要素を削除した
新しいマップを作成します。
・例
iex> list = %{ "ID" => 1, "URL" => "yttm-work.jp"}
%{ "ID" => 1, "URL" => "yttm-work"}
iex> list2 = Map.delete(list, "ID")
%{"URL" => "yttm-work.jp"}
・要素削除(複数)
マップの要素を複数個一括で削除したい場合はMap.dropを使用して
新しいマップを作成します。
・例
iex> list = %{ "ID" => 1, "URL" => "yttm-work.jp"}
%{ "ID" => 1, "URL" => "yttm-work"}
iex> list2 = Map.drop(list, ["ID", "URL"])
%{}
■キーワードリスト
キーワードリストはリストの各要素がタプルになっている特殊なリストです。
●キーワードリスト特性
・各要素はタプル
キーワードリストの要素は全てタプル型です。
・タプルの要素数は固定
タプルの要素数は固定されており、二つ以外は設定できません。
・キーはアトム型
キー(タプルの第一要素)は必ずタプル型となっています。
・キーは順序付けあり
マップと違い、キーワードリストはきちんと順序付けされています。
・キーの一意性は保障されない
マップはキーの一意性は保障されていますが、キーワードリストのキーは
一意性が保障されていないので、同じ名前のキーが設定される可能性があります。
例えばリストの1番目の要素のキーが「:Test」で2番目のキーも「:Test」ということが
許容されます。
●書式
キーワードリストの書式はアトムのショートカット記述を使用した方法と
正式にタプルを用いた方法の2種類があります。
・アトムショートカットの例
・書式例
[キー(アトム) 値, キー(アトム) 値, ...]
・具体例
[ID: 1, URL: "yttm-work.jp"]
・タプル使用の例
・書式例
[ { キー(アトム), 値 }, { キー(アトム), 値 }, ... ]
・具体例
[ { :ID, 1 }, { :URL, "yttm-work.jp" } ]
●参照
キーワードリストの値を参照する場合、変数名[キー]で参照できます。
・例
iex> list = [ID: 1, URL: "yttm-work.jp"]
[ID: 1, URL: "yttm-work.jp"]
iex> list[:ID]
1
iex> list[:URL]
"yttm-work.jp"
マップとは違い「変数名.キー」はエラーになるので注意して下さい。
・例
iex> list = [id: 1, url: "yttm-work.jp"]
[id: 1, url: "yttm-work.jp"]
iex> list[:id]
list.id
iex> list[:URL]
** (ArgumentError) argument error
:erlang.apply([id: 1, url: "yttm-work.jp"], :id, [])