Referencing Structs inside a Cell Array in Matlab - arrays

I'm dealing with a Matlab data structure which is analagous to "MyCellArray" in the following example:
% Create a Struct of string values inside a Cell Array
myCellArray = cell(3,1)
myStruct1 = struct('valA','aaa111','valB','bbb111','valC','ccc111')
myStruct2 = struct('valA','aaa222','valB','bbb222','valC','ccc222')
myStruct3 = struct('valA','aaa333','valB','bbb333','valC','ccc333')
myCellArray{1} = myStruct1
myCellArray{2} = myStruct2
myCellArray{3} = myStruct3
I'd like to be able to efficiently extract some of the data into a new array:
% Extract all valA values from myCellArray
% ArrayOfValA = myCellArray(< somehow get all the valA values >)
DesiredResult = cellstr(['aaa111';'aaa222';'aaa333']) % Or something similar
I'm new to Matlab and I just can't get my head around the notation. I've tried things like:
ArrayOfValA = myCellArray{(:,1).valA} % This is incorrect notation!
The real data is over 500K lines long so I'd like to avoid for loops or other iterative functions if possible. Unfortunately I can't change the original data structure but I suppose I could take a copy and manipulate that (I tried using struct2cell but I just got into another mess!). Is it possible to do this in a fast and efficient way?
Many thanks.

The following appears to work in Octave. I assume it also works in MATLAB:
>> temp = {[myCellArray{:}].valA}
temp =
{
[1,1] = aaa111
[1,2] = aaa222
[1,3] = aaa333
}

Does
myCellAsMat = cell2mat(myCellArray);
ArrayOfValA = vertcat(myCellAsMat(:).valA);
work?
edit: or horzcat, depending on the dimension and desired output of your valA field.

Related

How to return the leaves of a struct as vector in Matlab?

Often I need to access the leaves of data in a structured array for calculations.
How is this best done in Matlab 2017b?
% Minimal working example:
egg(1).weight = 30;
egg(2).weight = 33;
egg(3).weight = 34;
someeggs = mean([egg.weight]) % works fine
apple(1).properties.weight = 300;
apple(2).properties.weight = 330;
apple(3).properties.weight = 340;
someapples = mean([apple.properties.weight]) %fails
weights = [apple.properties.weight] %fails too
% Expected one output from a curly brace or dot indexing expression,
% but there were 3 results.
If only the top level is a non-scalar structure array, and every entry below is a scalar structure, you can collect the leaves with a call to arrayfun, then do your calculation on the returned vector:
>> weights = arrayfun(#(s) s.properties.weight, apple) % To get the vector
weights =
300 330 340
>> someapples = mean(arrayfun(#(s) s.properties.weight, apple))
someapples =
323.3333
The reason [apple.properties.weight] fails is because dot indexing returns a comma-separated list of structures for apple.properties. You would need to collect this list into a new structure array, then apply dot indexing to that for the next field weight.
You can collect properties into a temporary structure array, and then use it as normal:
apple_properties = [apple.properties];
someapples = mean([apple_properties.weight]) %works
This wouldn't work if you had even more nested levels. Perhaps something like this:
apple(1).properties.imperial.weight = 10;
apple(2).properties.imperial.weight = 15;
apple(3).properties.imperial.weight = 18;
apple(1).properties.metric.weight = 4;
apple(2).properties.metric.weight = 7;
apple(3).properties.metric.weight = 8;
Not that I would advise such a structure, but it works as a toy example. In that case you could, do the same as the previous in two steps... or you could use arrayfun.
weights = arrayfun(#(x) x.properties.metric.weight, apple);
mean(weights)

Pythonic way in matlab to decompose array to variables

So I want to decompose array to multiple variables.
For example,
I have 'data' array of (136,9) size which is of double type.
I want to decompose the values of data(1,:) to multiple variables something like below:
[frm_id,seq_id,xmin,ymin,w,h,temp1,temp2,temp3] = data(1,:);
In python it was straightforward, but above code gives following error in matlab:
Insufficient number of outputs from right hand side of equal sign to satisfy
assignment.
I can go with something like
frm_id = data(1,1);
seq_id = data(1,2);
%ect
But I do believe there must be matlab (more neat) way to do this operation.
Thanks!
You can use num2cell to convert the matrix to a cell array then copy contents of the cell to each variable:
C = num2cell(data,1);
[frm_id,seq_id,xmin,ymin,w,h,temp1,temp2,temp3] = C{:};
I can only suggest you to create a function like this:
function [frm_id,seq_id,xmin,ymin,w,h,temp1,temp2,temp3] = myfunction (data)
frm_id = data(:,1);
seq_id = data(:,2);
xmin = data(:,3);
ymin = data(:,4);
w = data(:,5);
h = data(:,6);
temp1 = data(:,7);
temp2 = data(:,8);
temp3 = data(:,9);
so in your main code
[frm_id,seq_id,xmin,ymin,w,h,temp1,temp2,temp3] = myfunction(data);

Vectorizing and assigning structs and fields

I would like to vectorize operations with structs and have spent some hours searching but I couldn’t find the solution.
I have a struct as follows:
clear all
n= 10;
for i=1:n
mystruct(i).x = i;
mystruct(i).y = i;
mystruct(i).z = 0;
end
I want to add all x to all y values and assign them to z.
This works:
test1 = [mystruct.x] + [mystruct.y];
test2 = arrayfun(#(a)mystruct(a).x+mystruct(a).y,1:n);
However, assigning the array doesn’t:
mystruct.z = [mystruct.x] + [mystruct.y];
mystruct.z = mystruct.x + mystruct.y;
I can generate a new struct:
mystruct2 = struct('z',num2cell ([mystruct.x]+[mystruct.y]));
But the next operation again doesn't work:
mystruct.z = mystruct2.z;
I could of course use a for loop:
for i=1:n
mystruct(i).z = mystruct(i).x + mystruct(i).y;
end
But that’s not what I want as this would make my code quite nasty and will not work for parallel operations using "parfor".
How can I perform this operation?
I believe you want to use the deal function, which is used to distribute inputs to outputs and works with structures starting with MATLAB 7.
With appropriate use of [square brackets], you can use this:
[mystruct2.z] = deal([mystruct(1:n).x] + [mystruct(1:n).y]);
which outputs:
ans =
2 4 6
Yay!

Getting array from struct array in Matlab without loops

I have a binary image with some objects, and I want to get some characteristics of these objects.
I = imread('coins.png');
B = im2bw(I, 100/255); B = imfill(B, 'holes');
RP = regionprops(B, 'Area', 'Centroid');
RP becomes a structure array:
10x1 struct array with fields:
Area
Centroid
I need to make from this structure 2 arrays called Areas and Centroids.
How to make it without loops?
Using loops we can go this way:
N = numel(RP);
Areas = zeros(N, 1); Centroids = zeros(N, 2);
for idx=1:N,
Areas(idx) = RP(idx).Area;
Centroids(idx, :) = RP(idx).Centroid;
end
You can simply concat
Areas = [RP.Area];
Centroids = vertcat( RP.Centroid );
PS,
It is best not to use i as a variable name in Matlab.

How to slice a struct array?

How can I extract a specific field from each element of a Matlab struct array?
>> clear x
>> x(1).a = 6;
>> x(2).a = 7;
I'd like an array containing 6 and 7. Neither x(:).a nor x.a do what I want.
>> x(:).a
ans =
6
ans =
7
No problem - just use :
arr = [x.a];
It will concat all of the values that you need.
If you have a more complex data, you can use the curly bracers:
b(1).x = 'John';
b(2).x = 'Doe';
arr = {b.x};
For a multi-dimensional array, you need
reshape([x.a], size(x))
If elements of the struct are strings, the accepted solution concatenates all cells.
The more general
vertcat(x.a)
works in all cases.
Ref
Sadly, I am almost sure that MATLAB has no nice way of doing what you want. You will have to either use a for loop to construct a new array, or else go back and redesign your data structures. For example you might be able to use a struct-of-arrays rather than an array-of-structs.

Resources