プロが教えるわが家の防犯対策術!

ベクトルvから複数の要素を抽出し,新しいベクトルuを生成する方法には,以下のようにインデックスを指定する方法があります.

idx = [3 10 15 28];
u = v(idx);

この方法を拡張し,以下のようにN次元配列Aのi次元目のインデックスを指定することで複数の配列を抽出し,新しい配列Bを得ようと考えています.

idx = [3 10 15 28];
B = A(:,:, ・・・ ,:,idx,:, ・・・ ,:,:);

Aの次元Nはi以上の任意の値で,iは予め指定された値である場合,
配列Bを得る方法はございますでしょうか.
現在,私は以下のような方法で計算しておりますが,コマンド「eval」を用いて力技でしのいでいる感じで,最適な方法が他にあるのでは,と考えております.

N = length(size(A));
idx = [3 10 15 28];
i = 3;
buf = 'A(';
for s = 1:N
if s == i
buf = [buf 'idx'];
else
buf = [buf ':'];
end
if s < N
buf = [buf ','];
end
end
buf = [buf ')'];
B = eval(buf);

A 回答 (1件)

もしかするともう解決しているかも知れませんが…



個人的にはind2subとかをうまく使えばできるような気がしていたのですが、
ind2sub内もnargoutで制御されているのでNを自由に変えるのには向いていません。
ind2subと同じ処理を自分で書いて出力をセル配列か2次元配列で出せるようにすれば
できるかも知れませんがそこまでするのも…という感じです。

ただ、evalに入れるbufを少しずつ連結させながら増やしていくというのもなんかいたずらに
行数がかかってしまうので嬉しくないですね。

ということでshiftdimを使って、取り出したいindexを自分の好きな場所に動かしてしまえば、
いちいち取り出したいindexかどうかのif文も要らなくなりそうなので楽ですね。
あとlength(size(A))はndims(A)で実現できますので見た目すっきりします。
(どちらが速いかはわかりませんが…)
ということで書いてみました。

A=rand(3,4,5,6,7);
N=ndims(A);
k=3;
idx=[1 3];
tmp=shiftdim(A,k-1);% k次元を一番最初の次元に持ってくる
Sa=size(A);
st=size(tmp);
buf=['tmp(idx' repmat(',:',1,N-1) ');'];

B=shiftdim(eval(buf),N-k+1);% evlaで取りだした後、次元を元に戻す
Sb=size(B);

私自身が「Matlabでfor文を使いたくない教」の熱烈な信者ですので(笑)
若干トリッキーな感じになってるかも…
処理速度などは検討していません。結局evalから逃げるのは難しそうですね…

ind2subを使った方法がうまくできればいいのですが。
参考になれば幸いです。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!