elixir – リストとタプル

Pythonの勉強してたときにタプルってのが出てきて、はて?ってなった。
何のためにつかうのかわからないからだ。

Pythonだと上記のようになる。
そして誰もが一発で理解できてるであろうリストは、以下のようになる。

こんな解説をしてる書籍とかブログが多いんだけど、だから違いはなんなの?って感じがする。

そんなことはもう知ってるんだけど?

と言いたくなる。

わかってる人はわかってるんだろうけど、そんな人でもほとんどタプルは使ってないとか書いてたりする。

じゃぁタプルってなんなのよ?リストとどう違うのよって話。

どうも格納される仕組みが違うらしい。

メモリに関して

おそらくこういうことだと思う。

リストであるlistを定義。

この時点でメモリ上の空いてる場所に、list[0]からlist[4]までが当てはめられる。

アドレスは適当だけど、こんな感じ。

格納先アドレス リスト要素
0x1111 list[0]
0x4432 list[1]
0x2154 list[2]
0x1332 list[3]
0xA4ED list[4]

要するに アドレスが連続してない わけだ。

普通配列ってのはこうやってメモリに格納されるで、おそらくそうだと思う。

そしてそれぞれの要素が、次のインデックス値を持つ変数への アドレスを保持している

つまり、list[0]にはlist[1]へのアドレス(0x4432)が保持されてる。コンスセルってやつだね(つまり先頭に要素を追加するのは早いけど後ろに追加するのは要素分たどる必要があるので遅くなることがあるってこと)。

極端な話、もし配列の要素が1万個あって全要素を抜き出す場合、1万回メモリがアクセスされることになる。

新しく要素を増やしたい場合、増やした要素は空いてるメモリに格納される。

そしてタプルはリストとは違って、必ず連続したメモリ空間に配置されるらしい。

つまり、タプルのそれぞれの要素は次の要素へのアドレスを保持してないから、システムとしては要素の先頭から要素の終わりまで一気に読み込めば良い話。これが高速な理由。

更にいうと、次へのアドレスを持ってないがゆえに、書き換えちゃうと壊れちゃう。だから書き換え禁止になってる。

というのが俺の理解だ。

tmp00015

リストとタプルを試してみる

リスト

このリストの先頭に0を追加する。

--++演算子をつかって足しひきも可能。

ちなみに引き算の場合、マッチする箇所は先頭から指定した分だけになる。

上記の場合、2と4を全部消すなら、[2, 2, 4, 4, 4, 4]と個数分指定する必要がある。

※これ多分他に良い方法があると思うけど今はまだわからない

タプル

elixirはPythonのように()パーレンではなく{}ブレイスでタプルを指定する。

このt1の4つ目の要素を表示してみる。
emel/2を使う。

因みにput_elem/3を使うと、任意の場所の値を変更出来る。

もちろん本当に入れ替えるわけではなく、新しく変数が作られるだけなので、変数に束縛しなければその場限りということになる。
試しにt1を表示してみると、何も変わってない

結論

なんだかよくわからないけど、さらにいろいろ調べてみると、リストとタプルにはこんな特徴があった。

  • リストは要素nにアクセスするようなランダムアクセスには向いていない
  • タプルは大抵2~4要素を持たせて使うことが多い

つまり、こういうことか。

  • リストはデータのダンプなんかに使うのが良いかも。
  • タプルは結果を得るようなもののデータとしてJSONみたいに使うのが良いかも。

めちゃめちゃ自信ないけど、ここではこういうことにしておく。

PHPやJavaScriptの配列みたいな感覚で挑むと脳みそが燻製状態になる。

実は他にもコレクション系があったりする

さらにいろいろ調べてみると、elixirにはマップというものとか、キーワードリスト(リストの中にタプルを入れて連想配列っぽく使う方法)というものもあるので、PHPとかJavaScriptの配列、連想配列やオブジェクトみたいなものは実現できるので安心した。

おわり

次回は文字列とかやろうかな。特に決めてない。