だから私の質問は: myfunc(x,y) によって生成された変数の型をテストすることなく、セル配列 zout を埋める方法はありますか? そもそも構造体を使用する必要がありますか (そうであれば、それを設定する最良の方法は何ですか)?
@NotBoStyf が提供する答えはほとんどありませんが、完全ではありません。セル配列は正しい方法です。ただし、答えは関数からの出力の数に大きく依存します。
出力が 1 つだけの機能
この関数strcmp
には、配列である 1 つの出力しかありません。その理由は
zout{1,:} = strcmp(x,y)
zout の次元が N x 2 の場合、左側 ( zout{1,:}
) が右側から 2 つの出力を期待しているというエラー メッセージが表示されます。これは次の方法で修正できます。
[zout{1,:}] = num2cell(strcmp(x,y)); % notice the square brackets on the LHS
ただし、これを行う理由はまったくありません。zout
N x 1 セル配列として単純に定義し、結果を取得できます。
zout = cell(1,1);
x = 'a';
y = { 'a', 'b' };
zout{1} = strcmp(x,y);
% Referring to the results:
x_is_y_1 = zout{1}(1);
x_is_y_2 = zout{1}(2);
検討すべきケースがもう 1 つあります...
複数の出力を持つ関数
関数が複数の出力を生成する場合 (配列である単一の出力とは対照的に)、これは最初の出力のみをキャプチャします。複数の出力を生成する関数は、次のように定義されます。
function [outA,outB] = do_something( a, b )
outA = a + 1;
outB = b + 2;
end
ここでは、両方の出力引数を明示的にキャプチャする必要があります。それ以外の場合は、a
. 例えば:
outA = do_something( [1,2,3], [4,5,6] ); % outA is [2,3,4]
[outA,outB] = do_something( [1,2,3], [4,5,6] ); % outA is [2,3,4], outB is [6,7,8]
Z1 = cell(1,1);
Z1{1,1} = do_something( [1,2,3], [4,5,6] ); % Z1{1,1} is [2,3,4]
Z2 = cell(1,2);
Z2{1,1:2} = do_something( [1,2,3], [4,5,6] ); % Same error as above.
% NB: You really never want to have a cell expansion that is not surrounded
% by square brackets.
% Do this instead:
[Z2{1,1:2}] = do_something( [1,2,3], [4,5,6] ); % Z2{1,1} is [2,3,4], Z2{1,2} is [6,7,8]
これはプログラムで行うこともできますが、いくつかの制限があります。func
1 つの入力を受け取り、一定の (ただし不明な) 数の出力を返す関数が与えられ
たとします。inp
処理したい入力を含むcell 配列があり、結果を cell の周りに収集したいと考えていoutp
ます。
N = numel(inp);
M = nargout(@func); % number of outputs produced by func
outp = cell(N,M);
for i=1:N
[ outp{i,:} ] = func( inp{i} );
end
このアプローチには、いくつかの注意事項があります。
すべての出力をキャプチャします。これは常にあなたが望むものではありません。
すべての出力をキャプチャすると、多くの場合、関数の動作が変わる可能性があります。たとえば、このfind
関数は、1 つの出力のみが使用されている場合は線形インデックスを返し、2 つの出力が使用されている場合は行/列のインデックスを返し、3 つの出力が使用されている場合は行/列/値を返します。
可変数の出力を持つ関数では機能しません。これらの関数は として定義されfunction [a,b,...,varargout] = func( ... )
ます。 nargout
関数が出力リストで宣言されている場合、負の数を返します。これvarargout
は、生成される出力の数を Matlab が知る方法がないためです。
配列とセルの出力をセルにアンパックする
これまでのところすべて真実ですが、私が望んでいるのは一般的な解決策です。関数がセル出力を生成する場合、num2cell を使用できません。したがって、strcmp で機能したことは strcat では失敗し、その逆も同様です。ここでは、複数の出力を返す関数の場合、最初の出力のみを zout でキャプチャする必要があると仮定しましょう – Carl Witthoft
セルまたは配列を返すすべての関数に対して統一された出力構文を提供するには、アダプター関数を使用します。数値配列とセルを処理する例を次に示します。
function [cellOut] = cellify(input)
if iscell(input)
cellOut = input;
elseif isnumeric(input)
cellOut = num2cell(input);
else
error('cellify currently does not support structs or objects');
end
end
出力を 2 次元 cell 配列にアンパックするには、各出力のサイズが一定でなければなりません。M
出力を仮定します。
N = numel(inp);
% M is known and constant
outp = cell(N,M);
for i=1:N
outp(i,:) = cellify( func( inp{i} ) ); % NB: parentheses instead of curlies on LHS
end
出力は としてアドレス指定できますoutp{i,j}
。別のアプローチでは、出力のサイズを変えることができます。
N = numel(inp);
% M is not necessary here
outp = cell(N,1);
for i=1:N
outp{i} = cellify( func( inp{i} ) ); % NB: back to curlies on LHS
end
出力は としてアドレス指定できoutp{i}{j}
、出力のサイズはさまざまです。
次の点に注意してください。
Matlab セルは基本的に非効率的なポインターです。JIT コンパイラーは、数値配列と同様にそれらを常に最適化するとは限りません。
数値配列をセルに分割すると、かなりの量のメモリが消費される可能性があります。各分割値は実際には数値配列であり、サイズと型の情報が関連付けられています。数値配列形式では、これは配列ごとに 1 回発生します。配列が分割されると、これは要素ごとに 1 回発生します。