この記事のポイント
– MATLABの `()` は、多くの場合「同じ型のまま一部を取り出す」ために使います。
– セル配列とtableでは、`{}` を使うと「中身のデータ」を取り出す場面が増えます。
– `dir` の出力はセル配列ではなく構造体配列なので、`{}` の意味を混同しないことが大切です。
本文
MATLABを使い始めたとき、意外とつまずきやすいのが `()` と `{}` の違いです。
特に、数値配列では `A(1)` と書くのに、セル配列では `C{1}` が出てきたり、tableでは `T(:, “x”)` と `T{:, “x”}` の両方が使われたりします。さらに `dir` の結果を処理していると `{listing.name}` のような書き方も見かけます。
少し複雑そうに感じますが、ある考え方を意識すると違いについて整理できるようになるかと考えます。
一言でいうと、`()` は「コンテナの形を保って取り出す」、`{}` は「中身を取り出す」と考えると、多くの場面で理解しやすくなります。ただし、通常の数値配列には、セルのような「箱」はないため、基本的には `()` を使います。
まず通常の配列では `()` を使う
数値配列やstring配列など、通常の配列では `()` で要素や範囲を取り出します。
A = [10 20; 30 40];
x = A(1,2)この場合、`x` は `20` です。
row = A(1,:)とすれば、1行目を配列として取り出せます。
通常の配列では、基本的に `{}` は使いません。`{}` が関係してくる代表例は、セル配列やtableです。
セル配列では `()` と `{}` の意味が変わる
セル配列は「中に別のデータを入れられる箱の配列」です。1つのセルには、数値、文字、行列、構造体など、さまざまな型のデータを入れられます。
C = {"apple", [1 2 3]; "banana", magic(2)};ここで `C(1,1)` と `C{1,1}` は、似ていますが結果が違います。
a = C(1,1)これは、1行1列の「セル配列」を返します。つまり、箱ごと取り出しています。
一方で、
b = C{1,1}これは、セルの中身である `”apple”` を取り出します。
この違いが、セル配列で最も大切なポイントです。
– `C(1,1)`:セル配列として取り出す
– `C{1,1}`:セルの中身を取り出す
たとえば、セルの中に数値ベクトルが入っている場合、
v = C{1,2}とすれば `[1 2 3]` という中身の数値配列を取り出せます。
table型では「tableとして残す」か「中身を取り出す」かで選ぶ
table型でも、`()` と `{}` の違いは重要です。
T = table([1;2;3], [10;20;30], ["A";"B";"C"], ...
VariableNames=["ID","Value","Label"]);このtableから `Value` 列を取り出す場合、書き方によって結果が変わります。
T1 = T(:, "Value")これは、`Value` 変数だけを持つtableを返します。tableとして残るので、列名やtableとしての構造も残ります。
一方で、
x = T{:, "Value"}これは、`Value` の中身である数値配列を返します。
さらに、1つの変数を取り出すだけなら、ドット表記もよく使います。
x = T.Valueこの場合も、`Value` 変数の中身を配列として取り出します。
整理すると、次のようになります。
T(:, "Value") % tableとして取り出す
T{:, "Value"} % 中身の配列として取り出す
T.Value % 1つの変数の中身を取り出すtableで迷ったときは、「この後もtableとして扱いたいのか」「計算やプロットに使うために中身の配列がほしいのか」で選ぶと分かりやすくなります。
`dir` の結果で出てくる `{}` は何をしているのか
`dir` を使うと、ファイルやフォルダーの一覧を取得できます。効率よくdir関数を使うためには、配列・セル配列両方の使い方を知っておくと便利です。dir関数は対象となるフォルダパスを指定することで、そのフォルダ内に含まれるファイル情報をリストできる関数です。以下の場合は「現在のフォルダに含まれる.m形式のファイルをリストする」といった機能になります。
listing = dir("*.m");ここで大切なのは、`dir` の戻り値はセル配列ではなく、構造体配列だという点です。
`listing` には、たとえば次のようなフィールドがあります。
– `name`
– `folder`
– `date`
– `bytes`
– `isdir`
– `datenum`
1つ目のファイル名を取り出すなら、構造体のフィールド参照として次のように書けます。
firstName = listing(1).name一方で、複数のファイル名をまとめて取り出したいときに、次のような書き方を見かけます。
names = {listing.name}これは、構造体配列 `listing` の各要素にある `name` フィールドを、セル配列としてまとめる書き方です。
たとえば `listing.name` は、複数要素に対しては個別での値をそれぞれ別で出力してしまうため、後の解析などを考えると不便です。それを `{}` で囲むことで、ファイル名の一覧をセル配列として受け取れます。
names = {listing.name}; % 1行N列のセル配列
names{1} % 1つ目のセルの中身、つまりファイル名
names(1) % 1つ目のセルをセル配列のまま取得ここでも、セル配列の基本と同じです。
– `names(1)`:セルとして取り出す
– `names{1}`:セルの中身、つまり文字ベクトルを取り出す
また、`dir` の結果をtableに変換することもあります。
listing = dir("*.m");
tbl = struct2table(listing);構造体配列もテーブル型にすることで、扱いやすくなる場合があります。
まとめ:迷ったら「型」と「ほしい結果」で考える
MATLABの `()` と `{}` は、記号だけで覚えようとすると混乱しやすいですが、型と結果に注目すると整理できます。
通常の配列では、基本的に `()` を使います。セル配列では、`()` はセル配列として取り出し、`{}` はセルの中身を取り出します。tableでは、`()` はtableとして取り出し、`{}` は中身の配列として取り出します。`dir` の結果は構造体配列なので、`{listing.name}` のような書き方は、フィールド値をセル配列にまとめるためのものです。
実務では、「この後に何をしたいか」が選び方の基準になります。表示や抽出の途中でtable構造を残したいなら `()`、計算・比較・文字列処理などに使う中身がほしいなら `{}` やドット表記を検討するとよいかと考えます。
よくある質問
Q. セル配列では、いつも `{}` を使えばよいですか?
中身を使いたいときは `{}` が便利です。ただし、セル配列の一部をセル配列のまま置き換えたい場合や、複数セルをまとめて扱いたい場合は `()` を使います。
Q. tableでは `T.Value` と `T{:, “Value”}` のどちらを使うべきですか?
1つの変数を取り出すだけなら `T.Value` が読みやすいことが多いです。複数列をまとめて配列として取り出したい場合は `T{:, [“A”,”B”]}` のような書き方が役立ちます。
おわりに
MATLABのインデックス指定は、配列、セル配列、table、構造体配列が混ざると急に難しく見えます。ただ、型ごとの考え方を一度整理しておくと、データ整理やファイル処理のコードがかなり読みやすくなります。SCISELでは、MATLABコードの整理、教育資料化、既存スクリプトの読み解き支援なども行っています。「この書き方の意味を説明しづらい」と感じるコードがある場合は、実務に合わせた形で整理をお手伝いできます。
SCISEL
MATLAB LabVIEWで困った方へ 支援・代行により研究や開発のサポートを行います
参考リンク
– MathWorks: Array Indexing
– MathWorks: Access Data in Cell Array
– MathWorks: Access Data in Tables
– MathWorks: dir
