Как преобразовать массив ячеек {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)