How to programmatically select which array dimension to address

23 visualizzazioni (ultimi 30 giorni)
I've run across this issue a few times, and I'm wondering if there's an elegant way to handle it.
Say I have a function that reorders the vectors/pages/etc of an N-D array along a specified dimension, but we don't really know how many dimensions this arbitrary array might have. How can I address the elements of the array? I can think of two solutions, neither of which seem particularly ideal.
On one hand, I could presume a maximum number of dimensions and just handle it with explicit cases. It wouldn't take that many cases to cover most practical scenarios. Let's say I presume a maximum of 5-D:
function outpict=reorderarray(myarray,whichdim)
sz=size(myarray);
reorderedVector=randi(sz(whichdim),[1 sz(whichdim)]);
switch whichdim
case 1
outpict=myarray(reorderedVector,:,:,:,:);
case 2
outpict=myarray(:,reorderedVector,:,:,:);
case 3
outpict=myarray(:,:,reorderedVector,:,:);
case 4
outpict=myarray(:,:,:,reorderedVector,:);
case 5
outpict=myarray(:,:,:,:,reorderedVector);
% we could go on ...
end
end
Alternatively, I could build the expression as a character array and use eval(). This seems like something I should avoid.
Is there a better way to do something like this?
  2 Commenti
DGM
DGM il 16 Mar 2021
Oof. I admit, I had struggled to find a good search query and could've done a better job. Thank you.

Accedi per commentare.

Risposta accettata

Walter Roberson
Walter Roberson il 16 Mar 2021
img = imread('flamingos.jpg');
imshow(reorderarray(img, 2));
imshow(reorderarray(img, 3));
imshow(reorderarray(img, 7));
function outpict = reorderarray(myarray,whichdim)
sz = size(myarray);
sz(end+1:whichdim) = 1; %in case asked for a dimension past the typical
idx = repmat({':'}, 1, length(sz));
idx{whichdim} = randperm(sz(whichdim));
outpict = myarray(idx{:});
end
  1 Commento
DGM
DGM il 16 Mar 2021
Auugh! It works!
I had run across a similar example in a very old book, but in the printing, the curly braces were parentheses. I just figured it was some old syntax that no longer worked. I didn't even think that of course it would be a cell array. I should've been paying attention.
Many thanks to you, Stephen, and John.

Accedi per commentare.

Più risposte (1)

John Chilleri
John Chilleri il 15 Mar 2021
Modificato: John Chilleri il 15 Mar 2021
Hello,
I wouldn't suggest this to be an elegant solution, but it has worked so far for a number of test cases.
% A is myarray
% wdim is whichdim
% ordering is reorderedVector
function C = reorderarray(A,wdim,ordering)
sz = size(A); % Acquire size
pA = 1:length(sz); % Create permutation vector
pA(1) = wdim; % Swap desired dimension with first dimension
pA(wdim) = 1;
sz2 = sz; % Track permuted size
sz2(1) = sz(wdim);
sz2(wdim) = sz(1);
B1 = permute(A,pA); % Permute matrix so desired dimension is first
B2 = B1(ordering,:); % Reorder rows and restructure as 2D array
B3 = reshape(B2,sz2); % Reshape back into original permuted shape
C = permute(B3,pA); % Undo the permutation
end
I'll note that the process makes sense intuitively, but I wouldn't guarantee its correctness. The reshape restoring order seems to work because MATLAB has consistent methods of indexing across functions.
Thanks!
  1 Commento
DGM
DGM il 16 Mar 2021
That works, but in my tests, it performs poorly in terms of execution time -- especially as array size increases. For a sample 100x10x10x10x10 array, it requires more than twice the time compared to the methods I described, and doubling the array size quintuples the time, whereas it only doubles it for the aforementioned methods.
I was actually surprised that the eval() method is actually slightly the fastest of the three. I've had it drilled into my head to avoid using eval(), but I'm not sure if this isn't a good use for it.

Accedi per commentare.

Community Treasure Hunt

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

Start Hunting!

Translated by