2

これは一般的な質問であり、特定の操作には関係ありません。関数が返すデータ型に関係なく、任意の関数の結果をセル配列の要素に書き込めるようにしたいと考えています。次の擬似コードを検討してください。

zout = cell(n,m);
myfunc = str2func('inputname'); %assume myfunc puts out m values to match zout dimensions
zout(1,:) = myfunc(x,y);

たとえば、xyが適切な次元の文字列または文字列のセルである場合、これは "inputname" == "strcat" に対して機能します。しかし、"inputname" == "strcmp" の場合、出力は論理配列であり、Matlab はエラーをスローします。私はする必要があります

zout(1,:) = num2cell(strcmp(x,y));

だから私の質問は:zoutによって生成された変数の型をテストせずにセル配列を埋める方法はありmyfunc(x,y ますか? structそもそもa を使用する必要がありますか (もしそうなら、それを設定する最良の方法は何ですか)?
(私は通常、Rユーザーであり、list変数を問題なく使用できます)

編集: スコープ全体を単純化するには、次の「要件」を追加します。ここでは、複数の出力を返す関数の場合、最初の出力のみを にキャプチャする必要があると仮定しましょうzout。しかし、この出力が N 値のベクトルまたはセルのベクトル (つまり、Nx1 セル配列) の場合、これらの N 値は にマップされzout(1,1:N)ます。

4

2 に答える 2

5

だから私の質問は: 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

ただし、これを行う理由はまったくありません。zoutN 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]

これはプログラムで行うこともできますが、いくつかの制限があります。func1 つの入力を受け取り、一定の (ただし不明な) 数の出力を返す関数が与えられ たとします。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

このアプローチには、いくつかの注意事項があります。

  1. すべての出力をキャプチャします。これは常にあなたが望むものではありません。

  2. すべての出力をキャプチャすると、多くの場合、関数の動作が変わる可能性があります。たとえば、このfind関数は、1 つの出力のみが使用されている場合は線形インデックスを返し、2 つの出力が使用されている場合は行/列のインデックスを返し、3 つの出力が使用されている場合は行/列/値を返します。

  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}、出力のサイズはさまざまです。

次の点に注意してください。

  1. Matlab セルは基本的に非効率的なポインターです。JIT コンパイラーは、数値配列と同様にそれらを常に最適化するとは限りません。

  2. 数値配列をセルに分割すると、かなりの量のメモリが消費される可能性があります。各分割値は実際には数値配列であり、サイズと型の情報が関連付けられています。数値配列形式では、これは配列ごとに 1 回発生します。配列が分割されると、これは要素ごとに 1 回発生します。

于 2012-06-29T15:16:38.207 に答える
0

値を代入するときは、代わりに中括弧を使用してください。使用する

 zout{1,:} = strcmp(x,y);

代わりに動作するはずです。

于 2012-06-26T14:27:33.550 に答える