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

Réponses (2)

Daniel M
Daniel M le 22 Oct 2019
Modifié(e) : Daniel M le 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 commentaires

Adam Danz
Adam Danz le 22 Oct 2019
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 le 22 Oct 2019
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 le 22 Oct 2019
Ah, right. I misread the sort() line.
Joe_Z
Joe_Z le 23 Oct 2019
Thanks Daniel a nice solution!
Daniel M
Daniel M le 23 Oct 2019
Modifié(e) : Daniel M le 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).

Connectez-vous pour commenter.

Adam Danz
Adam Danz le 22 Oct 2019
Modifié(e) : Adam Danz le 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 commentaires

Joe_Z
Joe_Z le 23 Oct 2019
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 le 23 Oct 2019
Modifié(e) : Adam Danz le 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.
Daniel M
Daniel M le 23 Oct 2019
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 le 23 Oct 2019
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.

Connectez-vous pour commenter.

Produits

Version

R2019b

Question posée :

le 22 Oct 2019

Commenté :

le 23 Oct 2019

Community Treasure Hunt

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

Start Hunting!

Translated by