MATLABでcell配列は何？なんか美味しそうですけど、普通の配列とどう違う？

# はじめに

<font color="#779900">**セリ**</font>と<font color="#779900">**セロリ**</font>って名前は似ていますが、どういう関係か？つい疑問に思ってしまったのですが、ここはそれについて説明する記事ではないです。

MATLABを使っていたら「<font color="#779900">**cell配列**</font>」という概念にぶつかるのですね。最初は「何それ美味しいの？」と思ってしまいました。

私は仙台でセリ鍋を食べたことがあるからこれは美味しそうに聞こえますよね。

全然関係ない話ですけど……。

基本的にMATLABで出番が多いのはただの「配列」（array）で、その配列の仕組みについて前回の記事で詳しく紹介しました。

https://qiita.com/phyblas/items/3a24b0e3745156a78d6b

しかしその他にも「cell配列」というものもよく使われています。ただの配列と似ていますが、違うところもあります。

それにこれは他の言語にはない概念でもあるので、他の言語の経験と知識から説明することはちょっと難しいです。Pythonのlist、tuple、setとも違います。

セロリが嫌で食べられない人もいるとよく聞いた話ですが、cell配列も最初はわけわからなくて嫌だという人もいるでしょうね。

でもちゃんと扱い方と必要性を理解したらこれもプログラミング言語として興味深いと感じます。

ということで、今回の記事では「cell配列」について解説します。


# cell配列の基本

## cell配列とは

簡単に言うとcell配列はMATLABにおける配列の一種です。

普通の配列と同じように色んなものが入っている配列ですが、普通の配列が同じデータ型のものから成されるのに対し、cell配列は色々違うものを同時に入れることができます。

これはPythonのlistやRuby、JavaScript、Dart、PHPなどの配列と似ていますね。ただし使い方はもっと複雑で、そう簡単にはいかないのです。

どう違うか以下説明していきます。


## cell配列の作成

普通の配列は`[ ]`で囲むことで作るのに対し、cell配列は`{ }`で作るのです。
```matlab
celery = {3 "4" '5'}
```

又は
```matlab
celery = {3,"4",'5'}
```

```:結果
celery =

  1×3 の cell 配列

    {[3]}    {["4"]}    {'5'}
```

こうやって違うものを入れてもそのまま問題ないのはcell配列の一番わかりやすい特徴です。

試しにこのような違うものを混ぜて普通の配列を作ってみたら勝手に同じものに変換させられますね。（変換できない場合はエラー）
```matlab
ar = [3 "4" '5']
```

```:結果
ar = 

  1×3 の string 配列

    "3"    "4"    "5"
```

配列の中にcell配列を入れることもできます。これは「ネスト」と呼びます。普通の配列はネストできません。
```matlab
{0,1,{2,3}}
```

```:結果
    {[0]}    {[1]}    {1×2 cell}
```

ネストできるだけでなく、普通の配列と同様に2次元又はまたともっと多い次元にできます。
```matlab
{1 "2" {3};'4' [] [5 6]}
```

```:結果
  2×3 の cell 配列

    {[1]}    {["2"     ]}    {1×1 cell}
    {'4'}    {0×0 double}    {[   5 6]}
```

ただし、普通の配列みたいに数学の演算子など使うことができません。
```matlab
{1}+{2}
```
```:結果
'cell' タイプのオペランドに対して、演算子 '+' はサポートされていません。
```

PythonのりlistやRubyの配列などは`+`で連結することができますが、MATLABのcell配列はそんなことはできませんね。


## cell配列の要素を取る

cell配列も配列だから、後ろに数字が入った括弧`( )`を書くことで要素にアクセスすることができます。ただし出てくるのはcell配列のままです。
```matlab
celery = {5 6 7}
celery(1)
```
```:結果
  1×1 の cell 配列

    {[5]}
```

1×1サイズになったとしてもまだcellという状態なので、そのまま使うことはできません。

cellは何か中身を包む宝箱で、解除しないと中身を取り出して扱うことができないですね。

cellの中の要素を取りたいなら`( )`の代わりに、`{ }`を使います。
```matlab
celery{1}
```
```:結果
     5
```

数値の配列を入れて同時に複数の要素を取ることもできますが、それがバラバラに出てきてしまいます。
```matlab
celery = {11 22 33 44 55};
celery{[1 3 4]}
```
```:結果
ans =

    11


ans =

    33


ans =

    44
```

そこで複数の配列を受け皿にすることができます。
```matlab
celery = {111 222 333 444 555 666};
[s,e,r,i] = celery{2:5}
```
```:結果
s =

   222


e =

   333


r =

   444


i =

   555
```

又は`[ ]`で囲んで配列に纏めます。
```matlab
ar = [celery{[1 3 4]}]
```
```:結果
ar =

   111   333   444
```

書き方はなんか複雑になってしまいますね。だからちゃんと理解しておかないとわけわからなくて悶々としてしまって困りますよね。


## 配列の中の全部のcellを解除する

`{:}`をcell配列の後ろに付けると中身が全部はみ出ます。ただしそのままだとバラバラに出てしまうので、配列に纏めたいなら`[ ]`で囲んでおきましょう。
```matlab
celery = {12 34 56};
[celery{:}]
```
```:結果
    12    34    56
```

また、もし要素が配列だったらそこで連結されます。
```matlab
celery = {[1;2] [3;4] [5;6]};
[celery{:}]
```
```:結果
     1     3     5
     2     4     6
```

ただし形が合わないなどの原因で連結できない場合はエラーになるので注意です。
```matlab
celery = {12 [3;4] 56};
[celery{:}]
```
```:結果
次を使用中のエラー: horzcat
連結する配列の次元が一致しません。
```

このエラーメッセージを見ると、実際にここで`horzcat`関数が呼ばれるという仕組みになっていますね。この動作を理解していなければこれはわけわからないエラーメッセージだと思って挫折してしまうかもしれません。


## 解除されたcell配列の中身を関数の入力に使う

cellからはみ出るものは変数に収める他に、直接そのまま関数に入れて使うこともできます。

例えば3つ数値を入れる必要がある関数を作って、それをcell配列に入れておいて、使う時に`{:}`ではみ出して関数に入力することができます。
```matlab
function soukei(a,b,c)
    fprintf("%d+%d+%d = %d\n",a,b,c,a+b+c)
end

celery = {1 2 5};
soukei(celery{:});
```
```:結果
1+2+5 = 8
```


## cell配列の要素を書き換える

普通の配列と同様に、cell配列の要素にアクセスできたら書き換えることができます。
```matlab
celery = {1 2 3};
celery{2} = [4 5];
celery
```
```:結果
celery =

  1×3 の cell 配列

    {[1]}    {[4 5]}    {[3]}
```

ただし`( )`でアクセスしたらエラーになるので、`{ }`を使わないとならないですね。
```matlab
celery = {1 2 3};
celery(2) = 4;
```
```:結果
double から cell に変換できません。
```

このエラーメッセージから見ると、代入しようとする時に勝手に変換しようとされますね。
ではもしその代わりにcellとして入れたら上手くいくのではないかと思ったら、本当にできてしまいます。
```matlab
celery = {4 5 6};
celery(2) = {[7 8]};
celery
```
```:結果
celery =

  1×3 の cell 配列

    {[4]}    {[7 8]}    {[6]}
```


# cell配列に関わる関数

## [cell](https://jp.mathworks.com/help/matlab/ref/cell.html)

`cell`という関数を使ったら空っぽなcell配列を作成することもできます。
```matlab
cell(4,2)
```
```:結果
  4×2 の cell 配列

    {0×0 double}    {0×0 double}
    {0×0 double}    {0×0 double}
    {0×0 double}    {0×0 double}
    {0×0 double}    {0×0 double}
```

ただし数値一つ入れたらそのサイズのとなります
```matlab
cell(3)
```
```:結果
  3×3 の cell 配列

    {0×0 double}    {0×0 double}    {0×0 double}
    {0×0 double}    {0×0 double}    {0×0 double}
    {0×0 double}    {0×0 double}    {0×0 double}
```


## [cell2mat](https://jp.mathworks.com/help/matlab/ref/cell2mat.html)

cell配列を解除して普通の配列にする時に`{ }`を後ろに付ける他に`cell2mat`を使うこともできます。これを使うと多次元のcell列をその形のまま普通の配列に変換できます。
```matlab
celery = {3 4 5;7 8 9};
cell2mat(celery)
```
```:結果
     3     4     5
     7     8     9
```

中の要素が配列だったら勝手に連結してしまいます。
```matlab
celery = {[1;4] [2 3;5 6];7 [8 9]}
mat = cell2mat(celery)
```
```:結果
celery =

  2×2 の cell 配列

    {2×1 double}    {2×2 double}
    {[       7]}    {[     8 9]}


mat =

     1     2     3
     4     5     6
     7     8     9
```

ただし連結できないような形だったらエラーになります。
```matlab
celery = {[5;6],[7 8]}
mat = cell2mat(celery)
```
```:結果
celery =

  1×2 の cell 配列

    {2×1 double}    {[7 8]}

次を使用中のエラー: cat
連結する配列の次元が一致しません。
```

エラーメッセージから見ると、中で`cat`関数が使われるという仕組みだとわかります。


## [mat2cell](https://jp.mathworks.com/help/matlab/ref/mat2cell.html)

`mat2cell`関数は`cell2mat`とは逆に、普通の配列からcell配列を作る関数です。

ただし使う時にそれぞれの軸でどのように配列を分割するか指定する必要があります。
```matlab
mat = ones(5,4);
mat2cell(mat,[2 2 1],[3 1])
```
```:結果
  3×2 の cell 配列

    {2×3 double}    {2×1 double}
    {2×3 double}    {2×1 double}
    {[   1 1 1]}    {[       1]}
```

1次元の横方向の配列の分割にもこのように使えます。
```matlab
mat = [2 2 1 3 3 3];
mat2cell(mat,1,[2 1 3])
```
```:結果
  1×3 の cell 配列

    {[2 2]}    {[1]}    {[3 3 3]}
```


## [num2cell](https://jp.mathworks.com/help/matlab/ref/num2cell.html)

`mat2cell`と違って、分割せずに単に配列をそのままcell配列に書き換えるなら`num2cell`を使います。
```matlab
mat = reshape(1:12,3,4)
celery = num2cell(mat)
```
```:結果
mat =

     1     4     7    10
     2     5     8    11
     3     6     9    12


celery =

  3×4 の cell 配列

    {[1]}    {[4]}    {[7]}    {[10]}
    {[2]}    {[5]}    {[8]}    {[11]}
    {[3]}    {[6]}    {[9]}    {[12]}
```

軸を指定たらその軸だけ纏めて一緒のcellに入れることになります。
```matlab
mat = ones(4,3,2);
celery1 = num2cell(mat,1)
celery2 = num2cell(mat,2)
celery3 = num2cell(mat,3)
celery13 = num2cell(mat,[1 3])
```
```:結果
  1×3×2 の cell 配列

celery1(:,:,1) = 

    {4×1 double}    {4×1 double}    {4×1 double}


celery1(:,:,2) = 

    {4×1 double}    {4×1 double}    {4×1 double}


  4×1×2 の cell 配列

celery2(:,:,1) = 

    {[1 1 1]}
    {[1 1 1]}
    {[1 1 1]}
    {[1 1 1]}


celery2(:,:,2) = 

    {[1 1 1]}
    {[1 1 1]}
    {[1 1 1]}
    {[1 1 1]}


celery3 =

  4×3 の cell 配列

    {1×1×2 double}    {1×1×2 double}    {1×1×2 double}
    {1×1×2 double}    {1×1×2 double}    {1×1×2 double}
    {1×1×2 double}    {1×1×2 double}    {1×1×2 double}
    {1×1×2 double}    {1×1×2 double}    {1×1×2 double}


celery13 =

  1×3 の cell 配列

    {4×1×2 double}    {4×1×2 double}    {4×1×2 double}
```


## [celldisp](https://jp.mathworks.com/help/matlab/ref/celldisp.html)

普段cell配列の中身が複数行の配列などだったらその配列の内容が表示されませんね。
```matlab
celery = {0,1;ones(2),zeros(3)}
```
```:結果
  2×2 の cell 配列

    {[       0]}    {[       1]}
    {2×2 double}    {3×3 double}
```

そこで`celldisp`関数を使ったらcell配列の中身を詳しく表示することができます。
```matlab
celldisp(celery)
```
```:結果
celery{1,1} =
 
     0

 
 
celery{2,1} =
 
     1     1
     1     1

 
 
celery{1,2} =
 
     1

 
 
celery{2,2} =
 
     0     0     0
     0     0     0
     0     0     0
```


# cell配列が出る関数

直接作らなくても実はcell配列は色んな場面で出てきます。

例えばexcelやcsvファイルなどを読み込むために使う[`readcell`関数](https://jp.mathworks.com/help/matlab/ref/readcell.html)です。

```celery.csv
1,セル,cell
2,セリ,seri
3,セロリ,celery
```
```matlab
readcell("celery.csv")
```
```:結果
  3×3 の cell 配列

    {[1]}    {'セル' }    {'cell'  }
    {[2]}    {'セリ' }    {'seri'  }
    {[3]}    {'セロリ'}    {'celery'}
```

又はjsonを読み込む[`jsondecode`関数](https://jp.mathworks.com/help/matlab/ref/jsondecode.html)。
```celery.json
[
    ["セロリ","celery"],
    [1,2],
    {"セリ":"seri"}
]
```
```matlab
jsondecode(fileread("celery.json"))
```
```:結果
  3×1 の cell 配列

    {2×1 cell  }
    {2×1 double}
    {1×1 struct}
```

それと、機械学習などで沢山な画像を読み込むのに使う`imageDatastore`も、`readall`メソッドを使ったらcell配列になります。これについて詳しくはこの記事で紹介しています。よろしければこれも読んでください。

https://qiita.com/phyblas/items/74f3788dd69c75c68e0b

このように色んな場面でcell配列が使われるので、どうやって対処するかわかっておくのも大事でしょう。


# 参考＆もっと読む

- [Matlab で JSON ファイルを扱う](https://qiita.com/gkhtnk/items/cffb2430bf0c1c8c68af)
- [MATLABにファイルデータを読みこむ関数](https://qiita.com/Monzo_N/items/ddcb5d80bed3a3ceb66c)
- [MATLABからファイルデータを書き出す関数](https://qiita.com/Monzo_N/items/0927e71b2b38f524001f)
- [MATLABの隠れたデータ型？　コンマ区切りリスト](https://qiita.com/h583/items/95a1a7e91212b190e49e)
- [ネスト化されたcellをアンネストする](https://qiita.com/jellied_unagi/items/ae8234a896397bfe7d70)


# 終わりに

ここまで読んで
<font color="#337700">セロリを食べたくなってきたでしょうか？</font>
大体cell配列についてわかってきたでしょうか。

他の言語と比べてちょっと風変わりな概念だからちょっとわかりにくいかもしれませんが、これを理解したら面白く感じます。