Main Content

コンマ区切りリスト

コンマ区切りリストとは

連続する数字をコンマで区切って入力すると、MATLAB® では "コンマ区切りリスト" が作成され、各値が個別に返されます。

1,2,3
ans =

     1


ans =

     2


ans =

     3

コンマ区切りリストを MATLAB 構造体や cell 配列などの大規模で複雑なデータ構造で使用すると、コードを簡易化することができます。

コンマ区切りリストの生成

cell 配列または MATLAB 構造体からコンマ区切りリストを生成できます。

cell 配列からのリストの生成

cell 配列から複数の要素を抽出すると、コンマ区切りリストが生成されます。4 行 6 列の cell 配列を定義します。

C = cell(4,6);
for k = 1:24
    C{k} = k*2;
end
C
C =

  4×6 cell array

    {[2]}    {[10]}    {[18]}    {[26]}    {[34]}    {[42]}
    {[4]}    {[12]}    {[20]}    {[28]}    {[36]}    {[44]}
    {[6]}    {[14]}    {[22]}    {[30]}    {[38]}    {[46]}
    {[8]}    {[16]}    {[24]}    {[32]}    {[40]}    {[48]}

第 5 列を抽出して、コンマ区切りリストを生成します。

C{:,5}
ans =

    34


ans =

    36


ans =

    38


ans =

    40

これは、リストを明示的に入力するのと同じことです。

C{1,5},C{2,5},C{3,5},C{4,5}

構造体からのリストの生成

次元の 1 つにある構造体配列のフィールドを抽出すると、コンマ区切りリストが生成されます。

まず、上で使用した cell 配列を、f1 から f6 の 6 個のフィールドをもつ 4 行 1 列の MATLAB 構造体に変換します。すべての行のフィールド f5 を読み取ると、MATLAB からコンマ区切りリストが返されます。

S = cell2struct(C,{'f1','f2','f3','f4','f5','f6'},2);
S.f5
ans =

    34


ans =

    36


ans =

    38


ans =

    40

これは、リストを明示的に入力するのと同じことです。

S(1).f5,S(2).f5,S(3).f5,S(4).f5

コンマ区切りリストからの出力の代入

コンマ区切りリストに含まれる連続した要素の一部またはすべてを、単純な代入ステートメントを使用して変数に代入できます。cell 配列 C を定義し、最初の行を変数 c1 から c6 に代入します。

C = cell(4,6);
for k = 1:24
    C{k} = k*2;
end
[c1,c2,c3,c4,c5,c6] = C{1,1:6};
c5
c5 =

    34
式によって返される出力数よりも少ない数の出力変数を指定すると、MATLAB では最初の N 個の出力がそれらの N 個の変数に代入され、残りの出力は無視されます。次の例では、MATLAB で C{1,1:3} が変数 c1c2c3 に代入され、C{1,4:6} が無視されます。
[c1,c2,c3] = C{1,1:6};
同じ方法で構造体の出力を代入することもできます。
S = cell2struct(C,{'f1','f2','f3','f4','f5','f6'},2);
[sf1,sf2,sf3] = S.f5;
sf3
sf3 =

    38
また、関数 deal を使用して同様の処理を実行することもできます。

コンマ区切りリストへの代入

コンマ区切りリストに複数の値を代入する最も簡単な方法は、関数 deal を使用することです。この関数では、その入力引数がコンマ区切りリストの要素に分配されます。

この例では、deal を使用してコンマ区切りリストの各要素を上書きします。まず、2 要素リストを初期化します。: をインデックスとして使用している場合、未定義の変数でコンマ区切りリストの代入を使用できないため、このステップが必要になります。詳細については、未定義変数へのコンマ区切りリストの代入を参照してください。

c{1} = []; 
c{2} = [];
c{:}
ans =

     []


ans =

     []

deal を使用して、リスト内の各要素を上書きします。

[c{:}] = deal([10 20],[14 12]);
c{:}
ans =

    10    20


ans =

    14    12

この例も同様に機能しますが、構造体フィールド内のベクトルのコンマ区切りリストを使用しています。

s(1).field1 = [[]];
s(2).field1 = [[]];
s.field1
ans =

     []


ans =

     []

deal を使用して、構造体のフィールドを上書きします。

[s.field1] = deal([10 20],[14 12]);
s.field1
ans =

    10    20


ans =

    14    12

コンマ区切りリストの使用方法

コンマ区切りリストの一般的な使用方法は、次のとおりです。

以下の節では、cell 配列を持つコンマ区切りリストの使用方法の例を示します。これらの例は構造体でも使用できます。

配列の作成

行列や配列を作成するときに、コンマ区切りリストを使用して、一連の要素を入力することができます。C{:,5} を使用して要素のリストを指定すると、MATLAB では 4 つの独立した要素が挿入されます。

C = cell(4,6);
for k = 1:24
    C{k} = k*2;
end
A = {'Hello',C{:,5},magic(4)}
A =

  1×6 cell array

    {'Hello'}    {[34]}    {[36]}    {[38]}    {[40]}    {4×4 double}

C セル自体を指定すると、MATLAB では cell 配列全体が挿入されます。

A = {'Hello',C,magic(4)}
A =

  1×3 cell array

    {'Hello'}    {4×6 cell}    {4×4 double}

配列の表示

リストを使用して、構造体や cell 配列の全部または一部を表示することができます。

A{:}
ans =

    'Hello'


ans =

  4×6 cell array

    {[2]}    {[10]}    {[18]}    {[26]}    {[34]}    {[42]}
    {[4]}    {[12]}    {[20]}    {[28]}    {[36]}    {[44]}
    {[6]}    {[14]}    {[22]}    {[30]}    {[38]}    {[46]}
    {[8]}    {[16]}    {[24]}    {[32]}    {[40]}    {[48]}


ans =

    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1

連結

次のように、コンマ区切りリストを大かっこ内に配置すると、リストから指定した要素が抽出され、連結されます。

A = [C{:,5:6}]
A =

    34    36    38    40    42    44    46    48

関数呼び出しの引数

関数呼び出しのコードを作成する際には、各引数をコンマで区切ったリストとして、入力引数を入力します。構造体や cell 配列にこれらの引数が保存されている場合は、代わりに構造体や cell 配列から引数リストの全部または一部を作成することができます。この方法は、引数の変数番号を渡す場合に特に役立ちます。

次の例では、関数 plot に複数の名前と値の引数を渡します。

X = -pi:pi/10:pi;
Y = tan(sin(X)) - sin(tan(X));
C = cell(2,3);
C{1,1} = 'LineWidth';
C{2,1} = 2;
C{1,2} = 'MarkerEdgeColor';
C{2,2} = 'k';
C{1,3} = 'MarkerFaceColor';
C{2,3} = 'g';
figure
plot(X,Y,'--rs',C{:})

関数の戻り値

MATLAB 関数では、複数の値を呼び出し側に返すこともできます。これらの値は、各値をコンマで区切ったリストで返されます。各戻り値をリストで表示する代わりに、構造体や cell 配列でコンマ区切りリストを使用することができます。この方法は、戻り値の数が可変である関数で非常に便利です。

次の例では、cell 配列に 3 つの値が返されます。

C = cell(1,3);
[C{:}] = fileparts('work/mytests/strArrays.mat')
C =

  1×3 cell array

    {'work/mytests'}    {'strArrays'}    {'.mat'}

高速フーリエ変換の例

関数 fftshift では、配列の各次元の左半分と右半分が入れ替えられます。ベクトル [0 2 4 6 8 10] の場合、出力は [6 8 10 0 2 4] です。多次元配列の場合、関数 fftshift では各次元で入れ替えが行われます。

関数 fftshift では、インデックスのベクトルを使用して入れ替えを実行できます。上記のベクトルの場合は、インデックス [1 2 3 4 5 6] が並へ替えられ、新しいインデックス [4 5 6 1 2 3] になります。次にこの関数では、このインデックス ベクトルを使用して要素の位置が変更されます。多次元配列の場合、fftshift では各次元のインデックス ベクトルが作成されます。コンマ区切りリストを使用すれば、この作業はずっと簡単になります。

次に、関数 fftshift を示します。

function y = fftshift(x)
    numDims = ndims(x);
    idx = cell(1,numDims);
    for k = 1:numDims
        m = size(x,k);
        p = ceil(m/2);
        idx{k} = [p+1:m 1:p];
    end
    y = x(idx{:});
end

この関数では、cell 配列 idx にインデック スベクトルが保存されます。この cell 配列の作成は比較的簡単です。N 次元ごとに、次元のサイズを決定し、中央に最も近い整数のインデックスを見つけます。次に、その次元の両半分を入れ替えるベクトルを作成します。

cell 配列を使用してインデックス ベクトルとインデックス演算用のコンマ区切りリストを保存すると、fftshift では、y = x(idx{:}) の演算 1 回のみで任意の次元の配列がシフトされます。明示的なインデックスを付ける場合は、関数で処理する次元ごとに、1 つの if ステートメントを記述する必要があります。

    if ndims(x) == 1
        y = x(index1);
    else if ndims(x) == 2
        y = x(index1,index2);
        end
    end

コンマ区切りリストを使わずにこれを処理するもう 1 つの方法として、各次元間をループして、一度に 1 つずつ次元を変換し、1 回ごとにデータを移動する方法があります。コンマ区切りリストを使用すれば、1 回の処理でデータを移動できます。コンマ区切りリストでは、任意数の次元の入れ替え操作が簡単になります。

コンマ区切りリストを使用した操作のトラブルシューティング

MATLAB でよく使用される演算やインデックス付け手法が、コマンド区切りリストに対して直接機能しないことがあります。この節では、コンマ区切りリストを使用するときに起こり得るいくつかのエラーの詳細と、その根底にある問題を解決する方法を説明します。

中間インデックス付けによりコンマ区切りリストが生成される

中かっこまたはドットを使用した複合インデックス式により、コンマ区切りリストが生成されることがあります。リストの個別の要素にアクセスするには、それらの要素にインデックスを付けなければなりません。

たとえば、double の 3 行 3 列の行列を 2 個含む、1 行 2 列の cell 配列を作成するとします。

A = {magic(3),rand(3)}
A =

  1×2 cell array

    {3×3 double}    {3×3 double}

中かっこのインデックス付けを使用して、両方の要素を表示します。

A{1,:}
ans =

     8     1     6
     3     5     7
     4     9     2


ans =

    0.7922    0.0357    0.6787
    0.9595    0.8491    0.7577
    0.6557    0.9340    0.7431

このように A にインデックス付けすると、cell 配列に含まれる両方の行列を含むコンマ区切りリストが生成されます。小かっこのインデックス付けを使用して、リスト内の両方の行列の (1,2) にあるエントリを取得することはできません。

A{1,:}(1,2)
Intermediate brace '{}' indexing produced a comma-separated list with 
2 values, but it must produce a single value when followed by 
subsequent indexing operations.

cell 配列内の両方の行列の (1,2) にあるエントリを取得するには、セルへのインデックス付けを個別に行います。

A{1,1}(1,2)
A{1,2}(1,2)
ans =

     1


ans =

    0.0357

式により、単一値ではなくコンマ区切りのリストが生成される

条件付きステートメント、論理演算子、ループ、および switch ステートメントの引数にはコンマ区切りリストを使用できません。たとえば、for ループを使用してコンマ区切りリストの内容を直接ループすることはできません。

最初の 3 つの素数の cell 配列を作成します。

A = cell(1,3);
A{1} = 2;
A{2} = 3;
A{3} = 5;

A{:} は、3 つの値のコンマ区切りリストを生成します。

A{:}
ans =

     2


ans =

     3


ans =

     5

A{:} で生成されたコンマ区切りリストを、for を使用してループするとエラーになります。

for c = A{:}
disp(c)
end
A brace '{}' indexing expression produced a comma-separated list with
3 values where only a single value is allowed.

A の内容をループするには、A{:} を大かっこで囲むことにより、値を連結して 1 つのべクトルにします。

for c = [A{:}]
disp(c)
end
     2

     3

     5

シンプルな代入を使用した複数要素の代入

配列とは異なり、シンプルな代入を使用して値をコンマ区切りリストの複数の要素に代入すると、エラーになります。たとえば、2 行 3 列の cell 配列を定義します。

B = cell(2,3);

:B のインデックスとして使用して配列のすべてのセルに 5 の値を代入すると、エラーになります。

B{:} = 5
Assigning to 6 elements using a simple assignment statement is not
supported. Consider using comma-separated list assignment.

この代入を行う 1 つの方法として、B{:} を大かっこで囲み、関数 deal を使用する方法があります。

[B{:}] = deal(5)
B =

  2×3 cell array

    {[5]}    {[5]}    {[5]}
    {[5]}    {[5]}    {[5]}

未定義変数へのコンマ区切りリストの代入

: をインデックスとして使用して、未定義の変数にコンマ区切りリストを代入することはできません。コンマ区切りリストへの代入の例では、: をインデックスとして使用して新しい値が代入される前に、変数 x が、明示的なインデックスを持つコンマ区切りリストとして定義されています。

x{1} = []; 
x{2} = [];
[x{:}] = deal([10 20],[14 12]);
x{:}
ans =

    10    20


ans =

    14    12

初期化されていない変数で同じ代入を実行すると、エラーになります。

[y{:}] = deal([10 20],[14 12]);
Comma-separated list assignment to a nonexistent variable is not
supported when any index is a colon (:). Use explicit indices or
define the variable before performing the assignment.

この問題を解決するには、x と同じ方法で y を初期化するか、関数 deal で生成された値の数を格納するのに十分な明示的なインデックスを使用して y を作成します。

[y{1:2}] = deal([10 20],[14 12])
y =

  1×2 cell array

    {[10 20]}    {[14 12]}

参考

| |