Struct array initialization without values - arrays

I have a structure
AStructX : 7x1 struct array with fields:
field1
field2
field3
field4
field5
Now I want to generate an empty 1x7 that looks like the previous struct, but with empty values.
I tried
AStructY = repmat(AStructX(1),1,7); but the values of AStructX is copied.
I tried
AStructY = repmat(AStructX(1),1,0); when I add values to it, it pass with MATLAB, but Coder generation fails with the following error message
??? Subscripting into an empty matrix is not supported.

Use cell2struct:
len = 7;
fn = fieldnames(AStructX)
AStructY = cell2struct(repmat({[]},numel(fn),len),fn)
That gives a 7x1 struct array with the same fields, empty contents. If you want a 1x7, simply transpose the array (i.e. AStructY = cell2struct(...).').

I'll make the following assumptions:
1. AStructX is 2-D.
2. You want the new structure to have the size size(AStructX').
3. The field names are not fixed.
To do this, you first need the fieldnames, then create a new struct with empty cells as values:
names = fieldnames(AStructX)'; %'// row vector
len = length(names); %// number of fields
for i=1:len
names{2,i} = cell(size(AStructX')); %'// the contents are empty
end
AStructY = struct( names{:} ); %// will take the names matrix columnwise
This will result in completely empty entries ([]), if you want to initialize the values to 0 instead, the line inside the loop becomes
names{2,i} = num2cell(zeros(size(AStructX'))); %'// initialize values to 0

Related

MATLAB: How to tabulate structs with same fields

I have use a 428×1 cell array called data
data = {[1×1 struct]
[1×1 struct]
....
[1x1 struct]}
These struct all have the same structure
data {2,1}
>>struct with fields
additional_model_information: 'H Series,S3150-S0-AW-04-02-C-F421,'
ceiling_fan_size_diameters_in_inches: '60'
airflow_efficiency_cfm_watt_low: '727'
airflow_efficiency_cfm_watt_high: '392'
The structure fields are the same for all 428 cells, and the fields values change in each struct.
How could i create a table that puts all of the structs together so that it shows all of the field values for each field? Pehaps using a nested for loop?
I eventually want to export this data to excel.
Let's say you've got your nx1 cell array of structs, data. This method doesn't assume you have 4 fields in your data or any knowledge of what they are called. You could even use it with structs with different fieldnames if you included some try/catch logic.
You can get the field names of a representative struct using fieldnames
fnames = fieldnames(data{1});
Then set up some output cell array out of the correct size
out = cell(numel(fnames), numel(data));
Then use nested loops to 1. loop through items in data and 2. loop through field names.
for n = 1:numel(data)
for field = 1:numel(fnames)
temp = data{n};
out{field, n} = temp.(fnames{field});
end
end
Finally, append the field names as the first column
out = [fnames, out];
And write the cell array to your Excel file
% File location, cell array, sheet, cell
xlswrite('C:\...\test.xlsx', out, 1, 'A1');
How about
T = cell(length(data) , 4);
for k = 1 : length(data)
T(k , :) = {data{k}.additional_model_information , ...
data{k}.ceiling_fan_size_diameters_in_inches, ...
data{k}.airflow_efficiency_cfm_watt_low, ...
data{k}.airflow_efficiency_cfm_watt_high};
end
Then you can use xlswrite to export to excel.

Matlab arrayfun with array of elements that are [1x4 struct]

I have a array, 'MY_STRUCTURES_Array', with single row and N columns. Each element is a [1x4 struct]. I want to extract a numeric valued 'thisField' from each structure of each [1x4 struct] element.
The result I am looking for is a 4xN array of the values for each 'thisField' value, where each row in this result corresponds to a colum in the [1x4 struct].
The code I am using is this:
arrayfun(#(x) (x.thisField), MY_STRUCTURES_Array);
Matlab returns the error
Attempt to reference field of non-structure array.
If I put the following in the command line,
MY_STRUCTURES_Array{1}
I get a list of all of the fields of the [1x4 struct].
If I put this in the command line,
MY_STRUCTURES_Array{1}.thisField
I get four answers, like this:
ans =
1
ans =
1
ans =
1
ans =
0
If I look at the size
size(MY_STRUCTURES_Array{1}.thisField)
Matlab says "Error using size", so I see this is not an array. But I'm not sure what it is.
I am not sure how to proceed to get the 4xN array I am looking for.
UPDATE
Output from command MY_STRUCTURES_Array returns a row array of [1x4 struct].
Output from whos MY_STRUCTURES_Array{1} returns nothing
Output from whos MY_STRUCTURES_Array returns:
Name Size Bytes Class Attributes
MY_STRUCTURES_Array 1x103 1371136 cell
Output from whos MY_STRUCTURES_Array{1}.thisField returns nothing
Output from MY_STRUCTURES_Array{1}.thisField was shown in the original post.
The fact that you're accessing MY_STRUCTURES_Array as MY_STRUCTURES_Array{1} indicates that it's a cell array, so I'll answer based on that.
Say we have MY_STRUCTURES_Array as a cell array of struct arrays:
MY_STRUCTURES_Array = {[1x4 struct], [1x4 struct], [1x4 struct]}
It contains N elements (here N = 3). Each element is a struct array with 4 elements and various fields. We want to extract the value of field foo, which contains a single number.
out = zeros(4, N);
for it = 1 : N
out(:, it) = [MY_STRUCTURES_Array{it}.foo];
end
out(i, j) now contains the value of MY_STRUCTURES_Array{j}(i).foo
EDIT:
Using arrayfun():
out = arrayfun(#(x) x.foo, cell2mat(MY_STRUCTURES_Array')')
This converts the cell array of struct arrays into a 2d struct array, then extracts field foo from each element.

Updating a struct with new values in a for loop

My image array: C_filled = 256x256x3270
What I would like to do is calculate the centroids of each image, and store each centroid corresponding to each 'slice'/image into an array. However, when I try to update the array, like a regular array, I get this error:
"Undefined operator '+' for input arguments of type 'struct'."
I have the following code:
for i=1:3270;
cen(i) = regionprops(C_filled(:,:,i),'centroid');
centroids = cat(1, cen.Centroid);% convert the cen struct into a regular array.
cen(i+1) = cen(i) + 1; <- this is the problem line
end
How can I update the array to store each new centroid?
Thanks in advance.
That's because the output of regionprops (i.e. cen(i)) is a structure, to which you try to add the value 1. But since you try to add the value to the structure and not one of its field, it fails.
Assuming that each image can contain multiple objects (and therefore centroids), it would be best (I think) to store their coordinates into a cell array in which each cell can be of a different size, contrary to a numeric array. If you have the exact same number of objects in each image, then you could use a numeric array.
If we look at the "cell array" option with code:
%// Initialize cell array to store centroid coordinates (1st row) and their number (2nd row)
centroids_cell = cell(2,3270);
for i=1:3270;
%// No need to index cen...saves memory
cen = regionprops(C_filled(:,:,i),'centroid');
centroids_cell{1,i} = cat(1,cen.Centroid);
centroids_cell{2,i} = numel(cen.Centroid);
end
and that's it. You can access the centroid coordinates of any image using this notation:centroids_cell{some index}.

How to name variables in a data array using a for loop

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

cell array of strings to matlab structure

I need to create a matlab structure as such ds=struct('name',{{'my_name_is'},{'matlab_thining_hair'}}) which stores as a 1x2 struct array with fields: name. A call to ds.name generates the output:
ds.name
ans =
'my_name_is'
ans =
'matlab_thining_hair'
Please note the single quotes in the output. They are important. That said, I need to create the above mentioned structure using the following variable:
X = [1x46 char] [1x47 char] i.e., 1x2 cell, which I believe is actually a cell array of strings. Among other things, I've tried the following:
Y = cell2struct(X, 'name', 1)'
which results in a 1x2 structure array with fields name, however a call to Y generates the output:
Y.name
ans = my_name_is
ans = matlab_thining_hair
Note that the single quotes in the output are missing, and albeit both Y and ds are 1x2 struct arrays with fields name, the field values are not formatted the same and the structures also vary in their bytes size. How to format the field values as character arrays?
In your first case you have created a struct with two fields whose values are cell arrays. The cell arrays are displayed with quotes.
In your second case your struct fields have char arrays which is what you want. Char arrays display without quotes.
You can verify this by typing in your command prompt {'abc'} and then 'abc'.
In your first case you can create non-cell array field values by passing the strings outside cell parenthesis.
ds=struct('name',{'my_name_is','matlab_thining_hair'})
Stick your char strings in another layer of cells before calling cell2struct. Instead of:
X = { 'foo', 'bar' }
Try:
X = { {'foo'}, {'bar'} }
That is, a 1-by-2 cell whose cell contents are themselves cells, not chars. Then cell2struct(X, 'name', 1) should give you a struct array with fields of cell arrays.
If your existing X is a cellstr, I think you can just call num2cell on it to push each cell down into another layer of cell indirection.

Resources