Как преобразовать массив ячеек {Mx1} массивов {1xN cell} в массив ячеек {1xN} из {Mx1 cell} массивов?

Предположим, что C - это массив ячеек с формой M & times; 1 (т.е. size(C) возвращает [M 1]) и что каждый элемент C, в свою очередь, является массивом ячеек с форма 1 & times; N.

Я часто хочу преобразовать такой массив ячеек в новый массив ячеек D, имеющий форму 1 & times; N, причем элементами являются массивы ячеек с формой M & times; 1 и такие, что C{i}{j} equals D{j}{i} для всех 0 < я & leq; M и 0 <   & le; N.

Я использую следующую чудовищность для этого

D = arrayfun(@(j) arrayfun(@(i) C{i}{j}, (1:M)', 'un', 0), 1:N, 'un', 0);

но потребность в этой операции возникает достаточно часто (в конце концов, это своего рода "транспонирование ячеек массива" ), о которой я думал, я бы спросил:

существует ли более стандартный способ выполнения этой операции?

Обратите внимание, что желаемый D отличается от

E = cat(2, C{:});

или, что эквивалентно,

E = cat(1, D{:});

Примером E является двумерный (M & times; N) массив ячеек, тогда как оба C и D являются одномерными клеточными массивами одномерных ячеек. Конечно, преобразование E обратно в C или D также является еще одной часто требуемой операцией (такого рода вещи никогда не заканчиваются с MATLAB), но я оставлю это для другого сообщения.


Мотивация этого вопроса выходит далеко за рамки проблемы, описанной выше. Оказывается, огромная часть моего кода MATLAB и еще большая часть моего времени и усилий по программированию MATLAB посвящена этой, по существу, непроизводительной работе по преобразованию данных из одного формата в другой. Конечно, преобразование формата неизбежно при выполнении какой-либо вычислительной работы, но с MATLAB я считаю, что делаю это намного больше или, по крайней мере, должен работать с ним намного сложнее, чем когда я работаю в других системах (например, Mathematica или Python/NumPy). Я надеюсь, что, создав свой репертуар MATLAB "трюки для преобразования формата", я смогу довести до более разумного уровня долю моего времени программирования MATLAB, которое я должен посвятить преобразованию формата. Суб >


P.S. Следующий код строит a C, подобный описанному выше, для M = 5 и N = 2.

uc = ['A':'Z'];
randstr = @() uc(randi(26, [1 4]));
M = 5;
rng(0);  % keep example reproducible
C = arrayfun(@(i) {randstr() i}, 1:M, 'un', 0)';

% C = 
%     {1x2 cell}
%     {1x2 cell}
%     {1x2 cell}
%     {1x2 cell}
%     {1x2 cell}
% >> cat(1, C{:});
% ans = 
%     'VXDX'    [1]
%     'QCHO'    [2]
%     'YZEZ'    [3]
%     'YMUD'    [4]
%     'KXUY'    [5]
%     

N = 2;
D = arrayfun(@(j) arrayfun(@(i) C{i}{j}, (1:M)', 'un', 0), 1:N, 'un', 0);

% D = 
%     {5x1 cell}    {5x1 cell}

Ответ 1

Вот небольшой трюк с использованием num2cell, который фактически работает с входами массива ячеек - ключ состоит в том, чтобы сначала развернуть C в 5-на-2 ячейки (эквивалентно cell(5,2)).

% Your example to produce C
uc = ['A':'Z'];
randstr = @() uc(randi(26, [1 4]));
M = 5;
rng(0);  % Keep example reproducible
C = arrayfun(@(i) {randstr() i}, 1:M, 'un', 0)';

% D = num2cell(reshape([C{:}],[N M]).',[1 M])
D = num2cell(reshape([C{:}],[size(C{1},2) size(C,1)]).',[1 size(C,1)])

или более просто

D = num2cell(cat(1,C{:}),1)

где D{:} возвращает:

ans = 

    'VXDX'
    'QCHO'
    'YZEZ'
    'YMUD'
    'KXUY'


ans = 

    [1]
    [2]
    [3]
    [4]
    [5]

Обратная операция перехода от D назад к C может быть выполнена с помощью:

% C = num2cell(reshape([D{:}],[N M]),[M N])
C = num2cell(reshape([D{:}],[size(D{1},1) size(D,2)]),[size(D,2) size(D{1},1)])

или

C = num2cell(cat(2,D{:}),2)

Таким образом, вы могли бы создать функцию, подобную следующей, которая будет работать в любом направлении:

transpose_cells = @(C)num2cell(cat(isrow(C)+1,C{:}),isrow(C)+1);
isequal(transpose_cells(transpose_cells(C)),C)