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

Answers (2)

Daniel M
Daniel M on 22 Oct 2019
Edited: Daniel M on 22 Oct 2019
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 Comments

What if the size of each dimension is the same (or contains at least 1 duplicate)?
Example: a= rand(4,4,4,4)
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?
Ah, right. I misread the sort() line.
Thanks Daniel a nice solution!
Daniel M
Daniel M on 23 Oct 2019
Edited: Daniel M on 23 Oct 2019
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).

Sign in to comment.

Adam Danz
Adam Danz on 22 Oct 2019
Edited: Adam Danz on 22 Oct 2019
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 Comments

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 on 23 Oct 2019
Edited: Adam Danz on 23 Oct 2019
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.
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].
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.

Sign in to comment.

Products

Release

R2019b

Asked:

on 22 Oct 2019

Commented:

on 23 Oct 2019

Community Treasure Hunt

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

Start Hunting!