Сохраните в .txt файл вложенный массив ячеек в его исходном формате: MATLAB [duplicate]

Я узнал, что добавил новую цель вместо расширения ( http://screencast.com/t/32hMPE8NWeR ). Чтобы исправить это, вам нужно добавить расширение iMessage в Target Dependencies и .appex для встраивания расширений приложений в фазах сборки

10
задан Luis Mendo 24 July 2016 в 15:49
поделиться

2 ответа

Этот процесс, преобразующий структуру данных в строку, которая позже может быть обнулена, называется serialization .

Существует функция сериализации для Octave , который может использоваться для этой цели, который поддерживает любой основной тип данных (не только массивы ячеек) с любым количеством измерений (не только 2d).

Примеры:

## Works for normal 2d numeric arrays
octave> a = magic (4);
octave> serialize (a)
ans = double([16 2 3 13;5 11 10 8;9 7 6 12;4 14 15 1])
octave> assert (eval (serialize (a)), a)

## Works for normal 3d numeric arrays with all precision
octave> a = rand (3, 3, 3);
octave> serialize (a)
ans = cat(3,double([0.53837757395682650507 0.41720691649633284692 0.66860079620859769189;0.018390655109800025518 0.56538265981533797344 0.20709955358395887304;0.86811365238275806089 0.18398187533949311723 0.20280927116918162634]),double([0.40869259684132724919 0.96877003954154328191 0.32138458265911834522;0.37357584261201565168 0.69925333907961184643 0.10937000120952171389;0.3804633375950405294 0.32942660641033155722 0.79302478034566603604]),double([0.44879474273802461015 0.78659287316710135851 0.49078191654039543534;0.66470978375890155121 0.87740365914996953922 0.77817214018098579409;0.51361398808500036139 0.75508941052835898411 0.70283088935085502591]))
octave> assert (eval (serialize (a)), a)

## Works for 3 dimensional cell arrays of strings
octave> a = reshape ({'foo', 'bar' 'qux', 'lol', 'baz', 'hello', 'there', 'octave'}, [2 2 2])
a = {2x2x2 Cell Array}
octave> serialize (a)
ans = cat(3,{["foo"],["qux"];["bar"],["lol"]},{["baz"],["there"];["hello"],["octave"]})
octave> assert (eval (serialize (a)), a)

Однако лучший вопрос - , почему вы хотите сделать это в первую очередь ? Если причина заключается в том, чтобы отправлять переменные между несколькими экземплярами Octave, рассмотрите возможность использования пакетов parallel и mpi , которые имеют специализированные функции для этой цели.

8
ответ дан carandraug 19 August 2018 в 03:56
поделиться
  • 1
    Благодаря! Я не знал, что это существовало в Октаве. И он поддерживает многомерные массивы! Я просто хочу использовать его, чтобы иметь больший контроль над тем, как отображаются массивы ячеек, в основном для кода golf – Luis Mendo 24 July 2016 в 18:59
  • 2
    @LuisMendo Я только что обсуждал с Энди (автором функции сериализации) на #octave о некоторых возможных улучшениях его функции. Вместо вложенных вызовов cat вы можете создать 1D-вектор, а затем reshape. Причина в том, что изменение формы - очень дешевая операция, в то время как несколько cat будут вызывать много накладных расходов на копирование. – carandraug 24 July 2016 в 19:04

Следующая функция работает для произвольных массивов с любой структурой вложенности и для любой формы массивов, если они все 2D-массивы. Многомерные массивы не поддерживаются (такие же, как mat2str).

Функция также позволяет указывать произвольные разделители строк и столбцов для массивов ячеек (например, выбирать между запятой и пробелом) и необязательно форсировать эти разделители для неячеистых массивов (таким образом, переопределение поведения mat2str »). Разделители по умолчанию в массивах ячеек ' ' для столбцов и '; ' для строк.

function y = array2str(x, col_sep, row_sep, sep_noncell)
% Converts a (possibly cell, nested) array to string representation
%
% Optional inputs col_sep and row_sep specify separators for the cell arrays.
% They can be arbitrary strings (but they should be chosen as per Matlab rules
% so that the output string evaluates to the input). Optional flag sep_noncell
% can be used to force those separators with non-cell arrays too, instead of
% the separators produced by mat2str (space and semicolon)

% Default values
if nargin<4
    sep_noncell = false;
end
if nargin<3
    row_sep = '; ';
end
if nargin<2
    col_sep = ' ';
end

x = {x}; % this is to initiallize processing
y = {[]}; % [] indicates content unknown yet: we need to go on
done = false;
while ~done
    done = true; % tentatively
    for n = 1:numel(y);
        if isempty(y{n}) % we need to go deeper
            done = false;
            if ~iscell(x{1}) % we've reached ground
                s = mat2str(x{1}); % final content
                if sep_noncell % replace mat2str's separators if required
                    s = regexprep(s,'(?<=^[^'']*(''[^'']*'')*[^'']*) ', col_sep);
                    s = regexprep(s,'(?<=^[^'']*(''[^'']*'')*[^'']*);', row_sep);
                end
                y{n} = s; % put final content...
                x(1) = []; % ...and remove from x
            else % advance one level
                str = ['{' repmat([{[]}, col_sep], 1, numel(x{1})) '}'];
                ind_sep = find(cellfun(@(t) isequal(t, col_sep), str));
                if ~isempty(ind_sep)
                    str(ind_sep(end)) = []; % remove last column separator
                    ind_sep(end) = [];
                end
                step_sep = size(x{1}, 2);
                str(ind_sep(step_sep:step_sep:end)) = {row_sep};
                y = [y(1:n-1) str y(n+1:end)]; % mark for further processing...
                x = [reshape(x{1}.', 1, []) x(2:end)]; % ...and unbox x{1},
                    % transposed and linearized
            end
        end
    end
end
y = [y{:}]; % concatenate all strings

Вышеупомянутая функция использует регулярные выражения для принудительного задания указанных разделителей в массивах, отличных от ячеек. Это работает в Matlab, но не в Octave, из-за ограничений в поддерживаемых шаблонах lookbehind. Следующая модифицированная версия позволяет избежать регулярных выражений и, таким образом, работает в Matlab и Octave. Только часть между if sep_noncell и соответствием end изменяется относительно первой версии.

function y = array2str(x, col_sep, row_sep, sep_noncell)
% Converts a (possibly cell, nested) array to string representation.
% Octave-friendly version
%
% Optional inputs col_sep and row_sep specify separators for the cell arrays.
% They can be arbitrary strings (but they should be chosen as per Matlab rules
% so that the output string evaluates to the input). Optional flag sep_noncell
% can be used to force those separators with non-cell arrays too, instead of
% the separators produced by mat2str (space and semicolon)

% Default values
if nargin<4
    sep_noncell = false;
end
if nargin<3
    row_sep = '; ';
end
if nargin<2
    col_sep = ' ';
end

x = {x}; % this is to initiallize processing
y = {[]}; % [] indicates content unknown yet: we need to go on
done = false;
while ~done
    done = true; % tentatively
    for n = 1:numel(y);
        if isempty(y{n}) % we need to go deeper
            done = false;
            if ~iscell(x{1}) % we've reached ground
                s = mat2str(x{1}); % final content
                if sep_noncell % replace mat2str's separators if required
                    for k = flip(find(~mod(cumsum(s==''''),2) & s==' ')) % process
                        % backwards, because indices to the right will become invalid
                        s = [s(1:k-1) col_sep s(k+1:end)];
                    end
                    for k = flip(find(~mod(cumsum(s==''''),2) & s==';'))
                        s = [s(1:k-1) row_sep s(k+1:end)];
                    end
                end
                y{n} = s; % put final content...
                x(1) = []; % ...and remove from x
            else % advance one level
                str = ['{' repmat([{[]}, col_sep], 1, numel(x{1})) '}'];
                ind_sep = find(cellfun(@(t) isequal(t, col_sep), str));
                if ~isempty(ind_sep)
                    str(ind_sep(end)) = []; % remove last column separator
                    ind_sep(end) = [];
                end
                step_sep = size(x{1}, 2);
                str(ind_sep(step_sep:step_sep:end)) = {row_sep};
                y = [y(1:n-1) str y(n+1:end)]; % mark for further processing...
                x = [reshape(x{1}.', 1, []) x(2:end)]; % ...and unbox x{1},
                    % transposed and linearized
            end
        end
    end
end
y = [y{:}]; % concatenate all strings

Как это работает

Я выбрал нерекурсивный подход, потому что я обычно более удобен с итерацией, чем с рекурсией.

Выход постепенно создается путем сохранения подстрок или пустых массивов ([]) в массиве ячеек (y). Пустой массив в ячейке y указывает, что «необходима дальнейшая обработка». Подстроки определяют «структуру» или, в конечном итоге, числовое, символьное или логическое содержимое на самом глубоком уровне вложенности ячеек.

. На каждой итерации первый пустой массив, найденный в y, заменяется фактическим содержимым , или подстроками и другими пустыми массивами, которые будут обработаны позже. Когда y не содержит пустого массива, процесс заканчивается, и все подстроки y объединяются, чтобы получить окончательный вывод строки.

Например, данный вход x = {[10 20], {'abc'; false; true;}}; и вызов y = array2str(x) ] массив y на каждом шаге представляет собой массив ячеек, содержащий:

'{'   []   ', '   []   '}'

'{'   '[10 20]'   ', '   []   '}'

'{'   '[10 20]'   ', '   '{'   []   '; '   []   '; '   []   '}'   '}'

'{'   '[10 20]'   ', '   '{'   ''abc''   '; '   []   '; '   []   '}'   '}'

'{'   '[10 20]'   ', '   '{'   ''abc''   '; '   'false'   '; '   []   '}'   '}'

'{'   '[10 20]'   ', '   '{'   ''abc''   '; '   'false'   '; '   'true'   '}'   '}'

, а последний, наконец, конкатенируется в строку

'{[10 20] {''abc''; false; true}}'

. В качестве примера с пользовательскими разделителями , array2str(x, ', ', '; ', true) даст

'{[10, 20], {''abc''; false; true}}'
5
ответ дан Luis Mendo 19 August 2018 в 03:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: