Elixir

Elixir: リストとタプルはいつどちらを使うのか

リストもタプルも、ともに複数のデータの容れ物です。値の型は問わず、いくつでも要素として納められます(「Elixir入門 02: 型の基本」参照)。

iex> list = [3.14, :pie, true, "Apple"]

[3.14, :pie, true, "Apple"]
iex> tuple = {3.14, :pie, true, "Apple"}
{3.14, :pie, true, "Apple"}

けれど、ふたつの仕組みは異なり、したがって使い途も変わります。ふたつの違いとしては、つぎのような点が挙げられます。

違い
タプル
リスト

サイズ
固定
可変

要素の操作
原則としてしない

ListのほかEnumの関数が使える

データの参照
速い
遅くなることがある


リストの仕組み

リストは「連結リスト」です。要素は値とつぎの要素への参照をもちます。要素を特定するインデックスは備えません。

qiita_12_001_001.png


タプルの仕組み

タプルは、連番インデックスをもった静的なデータ構造です。インデックス順に、まとめてメモリに納められます。

qiita_12_001_002.png


サイズに関わる違い

リストは要素を加えたり、除いたりすることが自由です。その数とそれぞれのデータによって、リストのサイズは変わります。タプルは、要素をまとめて納めたときに、サイズが決まります。要素の追加や削除は、実際上行われません。

サイズを得る関数は、リストがlength/1、タプルはtuple_size/1です。つぎのような処理の違いがあります。

関数
値の求め方
処理

length/1
数えて返す
遅い

tuple_size/1
あらかじめ計算されている
速い


要素の追加や削除などの操作

リストはListのほかEnumモジュールの豊富な関数で操作できます。特定の要素を追加したり、削除したり、変更するだけでなく、すべての要素を取り出して処理できるのです。

タプルを操作するTupleモジュールの関数は多くありません。要素を操作したいときには、リストを使うことが推奨されています。要素を加えたり、書き替えたりする場合は、メモリに新たなタプルをつくることになるので、負荷が高くなってしまうからです。


To manipulate a collection of elements, use a list instead.

(「Tuple」より)



データの参照と取り出し

リストにはインデックスがなく、要素間の参照をたどることで値が取り出されます。つまり、最後の要素を参照するには、すべての要素を順にたどらなければならないということです。もっとも、すべての要素を列挙して処理するには差し支えなく、Enumモジュールの関数が使えます。

タプルの要素は、elem/2関数により、インデックスを与えてただちに取り出せます。ただし、Enumモジュールの関数は使えません。

iex> tuple = {:ok, "hello"}

{:ok, "hello"}
iex> elem(tuple, 1)
"hello"


適した使い途

リストは、要素を自由に操作でき、メモリの許すかぎり加えられます。タプルは、予め決まったデータのやり取りに向くでしょう。

データを操作したり、数が変わったり、とくに多くの数のデータを扱うにはリストが使われます。1件のデータの複数の属性値を表すときは、タプルが適しているでしょう。典型は、キーと値の組みです。関数の戻り値によく用いられます。たとえば、File.read/1は、ファイル読み込みの結果と内容をタプルで返します。

iex> File.read("path/to/existing/file")

{:ok, "... ファイルの中身 ..."}
iex> File.read("path/to/unknown/file")
{:error, :enoent}

また、タプルはパターンマッチングにも用いられます。

iex> tuple = {:ok, :example}

{:ok, :example}
iex> {:ok, atom} = tuple
{:ok, :example}
iex> atom
:example

属性の数が増えてくると、タプルよりマップの方がわかりやすいかもしれません。

iex> {100, 150, 50}

{100, 150, 50}
iex> %{x: 100, y: 150, z: 50}
%{x: 100, y: 150, z: 50}

リストとタプルを組み合わせることもできます。キーワードリストがまさにその例です(「Elixir入門 07: キーワードリストとマップ」参照)。

iex> point = [x: 100, y: 150, z: 50]

[x: 100, y: 150, z: 50]
iex> point == [{:x, 100}, {:y, 150}, {:z, 50}]
true


まとめ


  • リストもタプルも任意の型のデータを複数納められます。

  • リストとタプルの仕組みは異なるので、つぎの点で違いがあります。


    • サイズ

    • 要素の操作

    • データの参照



  • リストとタプルそれぞれの性質にあった使い途があります。


    • リスト: 要素を操作し、数が変わるデータ

    • タプル: 複数の属性をもった固定データ