Массив ячеек MATLAB для отдельных переменных

#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) , vs name, 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