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

Antworten (2)

Daniel M
Daniel M am 22 Okt. 2019
Bearbeitet: Daniel M am 22 Okt. 2019

1 Stimme

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 Kommentare

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

Melden Sie sich an, um zu kommentieren.

Adam Danz
Adam Danz am 22 Okt. 2019
Bearbeitet: Adam Danz am 22 Okt. 2019

0 Stimmen

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 Kommentare

Joe_Z
Joe_Z am 23 Okt. 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 am 23 Okt. 2019
Bearbeitet: Adam Danz am 23 Okt. 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 am 23 Okt. 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 am 23 Okt. 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.

Melden Sie sich an, um zu kommentieren.

Produkte

Version

R2019b

Gefragt:

am 22 Okt. 2019

Kommentiert:

am 23 Okt. 2019

Community Treasure Hunt

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

Start Hunting!

Translated by