Effacer les filtres
Effacer les filtres

Selecting data from a dynamically named ND array

6 vues (au cours des 30 derniers jours)
Brian Scannell
Brian Scannell le 18 Mai 2017
Modifié(e) : Stephen23 le 6 Nov 2018
I have a structure with fields of various dimensions - typically between 3 and 6. Each of the fields has one dimension that represents a sampling instance, but in some fields it is dimension 2, in others dimension 3 or 4. I need to extract a subset of the data from each of the fields by selecting samples along the relevant dimension, so if all of the fields were, say, 4D and the sampling dimension was 2 with ix as the selection, I could use:
flds = fieldnames(S.(inst))
for i = 1:numel(flds)
fld = flds{i};
S.(inst).(fld) = S.(inst).(fld)(:,ix,:,:);
clear fld
end; clear i
I can easily check the number of dimensions of the field and I can work out which dimension of the field I need to sample along, but I then end up with something like:
flds = fieldnames(S.(inst))
for i = 1:numel(flds)
fld = flds{i};
ndims = numel(size(S.(inst).(fld));
idir = find(size(S.(inst).(fld)) == Nsamples); % where Nsamples is the number of samples
if ndims == 3
if idir == 1
S.(inst).(fld) = S.(inst).(fld)(ix,:,:);
elseif idir == 2
S.(inst).(fld) = S.(inst).(fld)(:,ix,:);
else
S.(inst).(fld) = S.(inst).(fld)(:,:,ix;
end
elseif ndims == 4
if idir == 1
S.(inst).(fld) = S.(inst).(fld)(ix,:,:,:)
elseif idir == 2
% etc
% etc
end
clear fld
end; clear i
I wondered whether anyone could suggest a more elegant solution? I was thinking that it would be possible to dynamically generate the data selection (:,ix,:,:) as a text string and use it with eval, but I'm not sure that works with the dynamic naming of variables.
Any thoughts?

Réponse acceptée

Stephen23
Stephen23 le 18 Mai 2017
Modifié(e) : Stephen23 le 6 Nov 2018
For a start you might like to read this (if you want to write better code, then it can help you):
And then to solve your problem you do not need to write lots of if-s or use eval, in fact you can do solve your quite simply by creating a cell array of indices and using that to generate a comma-separated list:
>> X = randi(9,1,2,3,4);
>> C = {':',':',2,':'};
>> X(C{:})
ans(:,:,1,1) =
1 1
ans(:,:,1,2) =
8 2
ans(:,:,1,3) =
3 8
ans(:,:,1,4) =
2 4
Another alternative is to call subsref directly. The function subsref is what MATLAB uses to index into variables, but you can also call it directly. All you need to do is create a suitable structure input, it is not that hard but you should play around with it to understand how it works. For example:
>> subsref(X,substruct('()',C))
ans(:,:,1,1) =
1 1
ans(:,:,1,2) =
8 2
ans(:,:,1,3) =
3 8
ans(:,:,1,4) =
2 4
Clearly it is pretty trivial to construct that cell array: something like this (untested):
C = repmat({':'},1,totdim);
C{ixdim} = ix;
  2 commentaires
Brian Scannell
Brian Scannell le 18 Mai 2017
Ah, that looks ideal. I have found that there is nearly always a way to avoid using eval - your answer proves the point!
Many thanks, Brian
Stephen23
Stephen23 le 18 Mai 2017
@Brian: I am glad to help, and I hope that it works for you.

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Logical dans Help Center et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by