#arrays #matlab #variables #cell
#массивы #matlab #переменные #ячейка
Вопрос:
В настоящее время у меня есть функция, которую я запускаю в пакетном режиме. Он выводит свои результаты в массив ячеек. Я хотел бы экспортировать каждый из выходных данных из массива ячеек в их собственную переменную.
Таким образом, у меня есть идентификатор переменной, который записывает идентификатор каждого слоя. Этот процесс возможен вручную следующим образом:
>> output =
[300x300x2 double] [300x300x2 double] [300x300x2 double]
>> [a1,a2,a3]=deal(output{:});
Где число после a представляет идентификатор. Возможно ли автоматизировать эту команду, чтобы пользователь мог задать префикс (в данном случае: a), а идентификатор заполнялся автоматически? Например, я мог бы установить переменные, как показано ниже, и использовать их в deal
команде для присвоения имен моим новым переменным?
>> id =
1 2 3
>> prefix =
a
Есть идеи?
Спасибо.
Комментарии:
1. Мне удалось решить следующим образом:
prefix= 'r'; id = [1:1:3] for i=1:length(id) s = ['[' layer int2str(id) '] = deal(cell{i});']; eval(s); end
Ответ №1:
Вы можете создать свое собственное пользовательское выражение в виде строки, а затем оценить его с eval()
помощью (или evalin()
, если оно находится в функции, и вы хотите вернуть вывод в свою рабочую область).
function deal_output(output, id, prefix)
id = id(:);
vars = strcat(prefix, cellstr(num2str(id)))';
myexpr = ['[', sprintf('%s,', vars{1:end-1}), vars{end}, '] = deal(output{:})'];
evalin('caller', myexpr)
>> output = num2cell(1:3);
>> id = 1:3;
>> prefix = 'a';
>> deal_output(output, id, prefix)
a1 =
4
a2 =
5
a3 =
6
Также проверьте join.m
файл на FileExchange, чтобы избежать уродства sprintf
.
Комментарии:
1. Можно ли в любом случае превратить это в функцию?
Ответ №2:
Возможно, что-то вроде:
function dealinto(prefix, cellarray)
% DEALINTO
% USAGE
% dealinto('a', {'one', 'two', 'three'})
% Causes these variables to be set in the base workspace:
% a1: 'one'
% a2: 'two'
% a3: 'three'
for i=1:numel(cellarray)
assignin('base', [prefix num2str(i)], cellarray{i});
end
Если вы замените ‘base’ на ‘caller’ в приведенном выше, переменные будут записаны в рабочую область вызывающей функции. Однако я не рекомендую этого делать по той же причине, по которой я бы не рекомендовал вызывать LOAD без выходных аргументов внутри функции: произвольная запись в рабочее пространство запущенной функции не очень безопасна.
Если вам нужно что-то подобное для использования внутри функций, но вы не хотите, чтобы оно просто записывало переменные волей-неволей, вы можете сделать то же самое, что и LOAD, то есть предоставить вам структуру, поля которой являются переменными, которые вы бы создали в противном случае.
Комментарии:
1. Я предлагаю заменить
'base'
на'caller'
вassignin
инструкции, чтобы функцию можно было использовать и внутри функции.2. @Jonas, я упоминал об этом, но я не рекомендую это. Я почти привел
ws
аргумент к функции, но я думаю, что единственный разумный вариант использования этой функции — для интерактивного использования. Иногда людям нужно делать странные вещи, так что все работает.3.
[name, task, mode] = deal_into(regexp(file, '-', 'split')
не кажется странным. Например, Python позволяет вам делать что-то подобное без каких-либо дополнительных усилий, и это очень удобно, напримерparsed = parse(filename)
, vsname, task, mode = parse(file)
будет работать при условии, что функция возвращает кортеж правильной арности.
Ответ №3:
Вам действительно нужно выводить их как полностью отдельные переменные? Было бы намного эффективнее использовать динамические имена полей в структуре, поскольку это позволило бы избежать использования eval()
оператора. Смотрите блоги MATLAB, чтобы избежать eval()
В этом случае
m = length(output);
[a(1:m).data] = deal(output{:});
Это вернет структурный массив, добавляется вычисление длины, чтобы он работал для разных размеров выходного массива ячеек.
К каждому массиву можно получить индивидуальный доступ с помощью идентификационного номера.
a(1).data
a(2).data
a(3).data
Ответ №4:
Кажется, я не могу добавить комментарий, поэтому я добавляю ответ в форме вопроса ^_ ^
Не лучше ли предварительно создать список имен и проверить их в рабочей области вызывающего абонента, используя genvarname ?
Names = cell(1,numel(data))
for idx = 1:numel(data)
Names{idx} = [Prefix, num2str(idx)]
end
Names = genvarname(Names,who)
dealinto(Names, data)
предотвратило бы создание любых недопустимых имен в существующем рабочем пространстве, тогда dealto необходимо было бы изменить как
function dealinto(Names, Values)
for idx = 1:length(Names)
assignin('caller', Names(idx), Values(idx))
end