delete dimension based on user input

Dear Matlab users,
I have a 4D array and I want to delete a dimension based on user input. I have written the below code for this but it uses eval statements (which I have seen people warn against) and feels like this could be done in a more optimum manner. Any suggestions would be much appreciated.
%find input file and take user input (time dimension)
vtc = xff('73_zk18w7_036.RUN1_RS_undist_SCCTBL_3DMCTS_THPGLMF2c_IDENTITY_ALIGNED.vtc');
disp(['VTC dimensions are: ' num2str(size(vtc.VTCData))]);
timeDim = input('What dimension is time? ');
%delete user input time dimension
switch timeDim
case 1
index = '(1,:,:,:)';
case 2
index = '(:,1,:,:)';
eval(['vtc.VTCData=vtc.VTCData' index])
case 3
index = '(:,:,1,:)';
case 4
index = '(:,:,:,1)';
otherwise
disp('Input a dimension between 1 and 4');
end
eval(['vtc.VTCData=vtc.VTCData' index]);
vtc.VTCData = squeeze(vtc.VTCData);
Best,
Joe

답변 (2개)

Daniel M
Daniel M 2019년 10월 22일
편집: Daniel M 2019년 10월 22일

1 개 추천

This should work.
a = rand(4,3,2,5); % random 4D matrix
dim = 3; % let's remove 3rd dimension
numDims = 1:length(size(a)); % [1 2 3 4]
[~,permInd] = sort(dim == numDims); % [1 2 4 3]
b = permute(a,permInd); % rearranges a
b = b(:,:,:,1); % only takes first value of last dimension
We can test it:
c = squeeze(a(:,:,1,:));
isequal(b,c)
% ans = 1

댓글 수: 5

Adam Danz
Adam Danz 2019년 10월 22일
What if the size of each dimension is the same (or contains at least 1 duplicate)?
Example: a= rand(4,4,4,4)
Daniel M
Daniel M 2019년 10월 22일
I believe the solution still works. My test case still passes (isequal(b,c)), but maybe it is insufficient. Can you think of a more robust test case?
Adam Danz
Adam Danz 2019년 10월 22일
Ah, right. I misread the sort() line.
Joe_Z
Joe_Z 2019년 10월 23일
Thanks Daniel a nice solution!
Daniel M
Daniel M 2019년 10월 23일
편집: Daniel M 2019년 10월 23일
Note: my test case above isn't completely robust since squeeze will remove ALL singleton dimensions, not just the specified one. (But the solution itself will not do that).

댓글을 달려면 로그인하십시오.

Adam Danz
Adam Danz 2019년 10월 22일
편집: Adam Danz 2019년 10월 22일

0 개 추천

You can use classes overload subsref to implement custom indexing.
% Set up default index
S.type = '()';
S.subs = {':',':',':',':'};
% Choose dimension and replace that value with 1
timeDim = 3
S.subs{timeDim } = 1;
% Do indexing
vtc.VTCData = subsref(vtc.VTCData,S)
vtc.VTCData = squeeze(vtc.VTCData);
If you'd rather use the switch-case method, just do the indexing within the cases.
switch timeDim
case 1
vtc.VTCData = vtc.VTCData(1,:,:,:);
case 2
vtc.VTCData = vtc.VTCData(:,1,:,:);
case 3
vtc.VTCData = vtc.VTCData(:,:,1,:);
case 4
vtc.VTCData =vtc.VTCData(:,:,:,1);
otherwise
disp('Input a dimension between 1 and 4');
end
vtc.VTCData = squeeze(vtc.VTCData);

댓글 수: 4

Joe_Z
Joe_Z 2019년 10월 23일
Thanks a lot Adam, I wasn't so familiar with subsref it's been an intersting read and a much cleaner solution. Cheers!
Adam Danz
Adam Danz 2019년 10월 23일
편집: Adam Danz 2019년 10월 23일
That's the first time I've used it, actually. I doubt there are many situations where it should be used but this is one of them.
Daniel M
Daniel M 2019년 10월 23일
Note that the use of squeeze will remove ALL singleton dimensions, not just the one you indicated.
Say the variable A = rand(1,3,2,5), and you want to remove only the 3rd dimension. In my solution above, the output will be [1x3x5], whereas any solution that uses squeeze will be [3x5].
Adam Danz
Adam Danz 2019년 10월 23일
Good point. I'd personally avoid using squeeze here and let the singlton dimensions be. I only added it because the OP included it in his code at the end. But it's good you're bringing that to his attention.

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터File Exchange에서 Logical에 대해 자세히 알아보기

제품

릴리스

R2019b

질문:

2019년 10월 22일

댓글:

2019년 10월 23일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by