I currently have a function which I am batch running. It outputs its results to a cell array. I would like to export each of the outputs from the cell array to their own variable.
As such I have a variable id which records the ID of each layer. This process is possible manually as follows:
>> output =
[300x300x2 double] [300x300x2 double] [300x300x2 double]
>> [a1,a2,a3]=deal(output{:});
Where the number after a represents the ID. Is it possible to automate this command, so that the prefix (in this case: a) can be set by the user and the id filled in automatically? As in, I could have variables set as below, and use these in the deal command to name my new variables?
>> id =
1 2 3
>> prefix =
a
Any ideas?
Thanks.
You can construct your own custom expression as a string and then evaluate it with eval() (or evalin() if it's in a function and you want to return the output to your workspace).
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
Also check out the join.m file on FileExchange for avoiding the ugly sprintf.
Perhaps something like:
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
If you replace 'base' with 'caller' in the above, the variables will be written into the calling function's workspace. I don't recommend doing this, though, for the same reason that I would not recommend calling LOAD with no output arguments inside a function: arbitrarily writing into a running function's workspace isn't very safe.
If you need something like this for use inside of functions but don't want it just writing variables willy nilly, you could do the same thing that LOAD does, which is to give you a structure whose fields are the variables you would otherwise produce.
Do you really have to output them as completely separate variables? It would be much more efficient to use dynamic field names in a structure as this would avoid the use of the eval() statement. See the MATLAB blogs for avoiding eval()
In this case
m = length(output);
[a(1:m).data] = deal(output{:});
This will return a structure array, the length calculation is added so it'll work for different sizes of the output cell array.
Each array can be accessed individually with an id number.
a(1).data
a(2).data
a(3).data
I can't seem to add a comment so I'm adding an answer in the form of a question ^_^
Is it not better to pre-create the list of names and check them in the caller workspace using genvarname ?
Names = cell(1,numel(data))
for idx = 1:numel(data)
Names{idx} = [Prefix, num2str(idx)]
end
Names = genvarname(Names,who)
dealinto(Names, data)
would prevent any invalid names from being create in the existing work space, then dealto would need to be modified as
function dealinto(Names, Values)
for idx = 1:length(Names)
assignin('caller', Names(idx), Values(idx))
end
Related
I am currently post-processing a lot of .mat files (300+) created with a long simulation (3days+).
Each of these mat files contain several variables, each named after their position on a grid (yes, they've been created with eval).
I thus created a script that opens each of the files sequentially
s = what(pwd);
s = s.mat;
for i=1:length(s)
data = open(sprintf('%s',s{i,:}));
% here goes what I would like to do
end
What I am trying to do now is to extract the current name of the data component that fits a certain pattern.
Specifically, I know that in data there is a vector named coef_%i_%i and I would like to isolate it and assign it to a multi-dimensional array.
The second part I know how to do it, I can scan the variable name for the _ characters, isolate the integers and assign the vector to its appropriate location in the array.
My question is:
Is there in matlab a way to do something along the lines of vectorname = extractname('data.coef*');?
Assuming you have something like:
clear data
% create a dummy field
name = sprintf ( 'coef_%i_%i', randi(100,[2 1]) );
% a data struct with a field which starts "coef*"
data.(name) = rand;
% and your data field may contain some other fields?
data.other = [];
You can then extract out the fields which contain the coef string
function output = extractname ( data )
%extract the fieldnames from data:
fn = fieldnames(data);
% find all that have coef in them
index = cellfun(#isempty, strfind(fn,'coef'));
% remove any that dont have coef in them
fn(index) = [];
%You are then left with one(or more) that contain coef in the name:
output = fn;
end
If your data struct contains fields which may have "coef" elsewhere in the name you would need to go through them and check if coef is at the start. You should also check that at the end of your function that one and only one field has been found.
So I would like to optimize my code such that I can look through an array such as
{'one','two','three'}
and create corresponding variables defined as tables or arrays
such as
one = table()
two = table()
three = table()
I am aware of the eval function however I would like to use this function in a loop s.t I allocate values to the new variable right after i create it
If I am understanding your question properly, given a cell array consisting only of strings, you wish to create variables in your workspace where each variable is declared as a string using the names from this cell array.
You could use eval, but I'm going to recommend something other than eval. eval should be avoided and instead of iterating those reasons, you can read Loren Shure's article on eval.
In any case, I would recommend you place these variables as dynamic fields inside a structure instead. Do something like this:
s = struct()
strs = {'one', 'two', 'three'};
for idx = 1 : numel(strs)
s.(strs{idx}) = table();
end
In this case, s would be a structure, and you can access the variable by the dot operator. In this case, you can access the corresponding variables by:
d = s.one; %// or
d2 = s.two; %// or
d3 = s.three;
If you want to place this into a function per se, you can place this into a function like so:
function [s] = createVariables(strs)
s = struct();
for idx = 1 : numel(strs)
s.(strs{idx}) = table();
end
This function will take in a cell array of strings, and outputs a structure that contains fields that correspond to the cell array of strings you put in. As such, you'd call it like so:
strs = {'one', 'two', 'three'};
s = createVariables(strs);
However, if you really really... I mean really... want to use eval, you can create your workspace variables like so:
strs = {'one', 'two', 'three'};
for idx = 1 : numel(strs)
eval([strs{idx} ' = table();']);
end
To place this into a function, do:
function [] = createVariables(strs)
for idx = 1 : numel(strs)
eval([strs{idx} ' = table();']);
end
However, be warned that if you run the function above, these variables will only be defined in the scope that the function was run in. You will not see these variables when the function exits. If you want to run a function so that the variables get defined in the workspace after you run the function, then eval is not the right solution for you. You should thus stick with the dynamic field approach that I talked about at the beginning of this post.
In any case, this will create one, two and three as workspace variables that are initialized to empty tables. However, I will argue with you that the first line of code is easier to read than the second piece of code, which is one of the main arguing points as to why eval should be avoided. If you stare at the second piece of code long enough, then you can certainly see what we're trying to achieve, but if you read the first piece of code, you can ascertain its purpose more clearly.
I have an array within an array and I am trying to name the variables using a for loop as there are a lot of variables. When I use the following simple code Time1 = dataCOMB{1,1}{1,1}(1:1024, 1); it opens the first cell in an array and proceeds to open the first cell in the following array and finally defines all the values in column 1 rows 1 to 1024 as Time1. However I have 38 of these different sets of data and when I apply the following code:
for t = 1:38
for aa = 1:38
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
end
end
I get an error
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in Load_Files_working (line 39)
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
Basically I am trying to get matlab to call the first column in each data set Time1, Time2, etc.
The problem:
1)You'd want to extract in a cell row...
2) ...the first 1024 numbers in the 1st column...
3) ...from each of the first 38 cells of a cell array.
The plan:
1) If one wants to get info from each element of a cell array (that is, an array accessed via {} indexing), one may use cellfun. Calling cellfun(some_function, a_cell_array) will aggregate the results of some_function(a_cell_array{k}) for all possible k subscripts. If the results are heterogeneous (i.e. not having the same type and size), one may use the cell_fun(..., 'UniformOutput', false) option to put them in an output cell array (cell arrays are good at grouping together heterogeneous data).
2) To extract the first 1024 numbers from the first column of an numeric array x one may use this anonymous function: #(x) x(1:1024,1). The x argument will com from each element of a cell array, and our anonymous function will play the role of some_function in the step above.
3) Now we need to specify a_cell_array, i.e. the cell array that contains the first 38 cells of the target. That would be, simply dataCOMB{1,1}(1,1:38).
The solution:
This one-liner implements the plan:
Time = cellfun(#(x) x(1:1024,1), dataCOMB{1,1}(1,1:38), 'UniformOutput', false);
Then you can access your data as in this example:
this_time = Time{3};
Your error is with Time(t). That's not how you create a new variable in matlab. To do exactly what you want (ie, create variables names Time1, Time2, etc...you'll need to use the eval function:
for aa = 1:38
eval(['Time' num2str(aa) '= dataCOMB{1,1}{1,aa}(1:1024,1);']);
end
Many people do not like recommending the eval function. Others wouldn't recommend moving all of your data out of a data structure and into their own independently-named variables. So, to address these two criticisms, a better alternative might be to pull your data out of your complicated data structure and to put it into a simpler array:
Time_Array = zeros(1024,38);
for aa = 1:38
Time_Array(:,aa) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
Or, if you don't like that because you really like the names Time1, Time2, etc, you could create them as fields to a data structure:
Time_Data = [];
for aa = 1:38
fieldname = ['Time' num2str(aa)];
Time_Data.(fieldname) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
And, in response to a comment below by the original post, this method can be extended to further unpack the data:
Time_Data = [];
count = 0;
for z = 1:2;
for aa = 1:38
count = count+1;
fieldname = ['Time' num2str(count)];
Time_Data.(fieldname) = dataCOMB{1,z}{1,aa}(1:1024,1);
end
end
I have an array of structures.
I'm trying to select several records from the array, that match some condition.
I know there's this option: (For example array A with field f1):
A([A.f1]==5)
Which would return all the records that have f1 = 5.
But I want to do it for several different fields, in a loop. I saved the fields names in a cell array, but I don't know how to do the same with a dynamic field name.
I know there's the 'getfield' function, but it only selects a field from a single structure.
Is there a way to do it?
Thanks!
To access dynamically a field of a structure:
% Create example structure
s.a = 1;
s.b = 2;
% Suppose you retrieve the fieldnames (or hardcode them fnames = {'a','b'})
fnames = fieldnames(s);
The you can retrieve e.g. the second one:
s.(fnames{2})
In a loop
for f = 1:numel(fnames)
s.(fnames{f})
end
In your case:
A([A.(fnames{ii})] == n)
This code will run through the first 5 records of your dynamical names
for i=1:5
eval(['A([A.' cell_array{i} ']==5)'])
end
I have never used matlab before so excuse this very basic question.
Basically I have a function that returns multiple variables, defined like so:
function [a, b, c]=somefunction(x, y, z)
I know I can get the return values as follows:
[a,b,c] = somefunction(1,2,3);
Now what I would like to do instead is save multiple runs of somefunction into an array and then retrieve them later. I tried:
results = [];
results = [results somefunction(1,2,3)];
results = [results somefunction(4,5,6)];
And then I tried accessing the individual runs as:
% access second run, i.e. somefunction(1,2,3) ?
a = results(2, 1);
b = results(2, 2);
c = results(2, 3);
but this tells me that the index is out of bound because size(results) = [1,99654] (99654 is the number of results I need to save). So it does not appear to be an array? Sorry for this basic question, again I have never used matlab.
When you combine arrays with [ ... ], you're concatenating them, creating one long flat array. For example, if call 1 returns 3 elements, call 2 returns 8 elements, and call 3 returns 4 elements, you'll end up with a 14-long array, and no way of knowing which elements came from which function call.
If you want to keep the results from each run separate, you can stash them in a cell array. You still need a comma-separated list on the LHS to get all the multiple argouts. The {}-indexing syntax, as opposed to (), "pops" contents in and out of cell elements.
Let's store the results in a k-by-n array named x, where the function returns n outputs and we'll call it k times.
x = cell(2, 3); % cell(k, n)
% Make calls
[x{1,1}, x{1,2}, x{1,3}] = somefunction(1,2,3);
[x{2,1}, x{2,2}, x{2,3}] = somefunction(4,5,6);
% Now, the results of the ni-th argout of the ki-th call are in x{ki,ni}
% E.g. here is the 3rd argout from the second call
x{2,3}
You could also store the argouts in separate variables, which may be more readable. In this case, each will be a k-long vector
[a,b,c] = deal(cell(1,2)); % cell(1,k)
[a{1}, b{1}, c{1}] = somefunction(1,2,3);
[a{2}, b{2}, c{2}] = somefunction(1,2,3);
And of course this generalizes to loops, if your somefunction inputs are amenable to that.
[a,b,c] = deal(cell(1,nIterations));
for k = 1:nIterations
[a{k}, b{k}, c{k}] = somefunction(1,2,3);
end
Details are in the doco at http://www.mathworks.com/help/matlab/cell-arrays.html or doc cell.
(Side note: that results(1, 2) in your post ought to succeed for an array of size [1,99654]. Sure you didn't do results(2, 1)?)