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
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 个评论

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!
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).

请先登录,再进行评论。

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 个评论

Thanks a lot Adam, I wasn't so familiar with subsref it's been an intersting read and a much cleaner solution. Cheers!
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.

请先登录,再进行评论。

类别

帮助中心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