Reputation: 35331
The code below produces a cell array containing n (=210) 2x3x4
-shaped n-d arrays.
n = prod(5:7);
makendarray = @(i) reshape(1:24, 2:4) + (i * 1000);
ndarrays = cellfun(makendarray, num2cell(1:n), 'un', 0);
For each i ∈ {1, … ,n}, the contents of the i-th n-d array are all integers whose initial digits match those of i. For example, for i = 123:
>> ndarrays{123}
ans(:,:,1) =
123001 123003 123005
123002 123004 123006
ans(:,:,2) =
123007 123009 123011
123008 123010 123012
ans(:,:,3) =
123013 123015 123017
123014 123016 123018
ans(:,:,4) =
123019 123021 123023
123020 123022 123024
I want to assemble all these n-d arrays into a larger [5x6x7x2x3x4 double]
n-d array X
in such a way that expressions of the form X(i,j,k,:,:,:)
will correspond to one of the original smaller n-d arrays. This last requirement is the one that's giving me difficulty.
I have no problem producing the larger [5x6x7x2x3x4 double]
n-d array from the smaller ones, but expressions of the form X(i,j,k,:,:,:)
do not produce one of the original smaller n-d arrays.
Below is an example of one of the things I've tried; the last output should match below should match the output shown for ndarrays{123}
above, but doesn't:
>> X = reshape(cell2mat(ndarrays), [5:7 2:4]);
>> [idx{1:3}] = ind2sub(5:7, 123);
>> squeeze(X(idx{:}, :, :, :))
ans(:,:,1) =
62001 62003 62005
167001 167003 167005
ans(:,:,2) =
62007 62009 62011
167007 167009 167011
ans(:,:,3) =
62013 62015 62017
167013 167015 167017
ans(:,:,4) =
62019 62021 62023
167019 167021 167023
EDIT: OK, by (pretty much blind) trial-and-error I found that the following does the trick:
tmp = cellfun(@(c) reshape(c, [1 24]), ndarrays, 'un', 0);
X = reshape(cat(1, tmp{:}), [5:7 2:4]);
IOW: linearize the subarrays before passing them to cat(1, ...)
. I'm surprised that it's necessary to explicitly perform this linearization step: it's what I expect MATLAB to do by default (in cell2mat
, for example).
Be that as it may, is there a better (or at least clearer/easier to understand) way to achieve the same effect?
(BTW, for this problem, the initial shape of ndarray
is given and not subject to change. IOW, solutions that require modifying the makesubarray
function in the example do not fit the situation I'm dealing with.)
EDIT2: In reference to Luis Mendo's answer, here's the output (copy-pasted verbatim from my MATLAB workspace) of a small script (with echo on
), showing the sizes of various items:
n = prod(5:7);
makendarray = @(i) reshape(1:24, 2:4) + (i * 1000);
ndarrays = cellfun(makendarray, num2cell(1:n), 'un', 0);
size(ndarrays)
ans =
1 210
size(permute(ndarrays, [2 3 4 1]))
ans =
210 1
size(cell2mat(permute(ndarrays, [2 3 4 1])))
ans =
420 3 4
echo off;
Upvotes: 1
Views: 79
Reputation: 112749
You can achieve it with a little bit of permute
and reshape
. The logic of this approach can be followed by observing size(X)
at the end of each step (indicated in the comments):
X = cell2mat(permute(ndarrays(:), [2 3 4 1])); %// size [2 3 4 210]
X = permute(X, [4 5 6 1 2 3]); %// size [210 1 1 2 3 4]
X = reshape(X, [7 6 5 2 3 4]); %// size [7 6 5 2 3 4]
X = permute(X, [3 2 1 4 5 6]); %// size [5 6 7 2 3 4]
Upvotes: 1