How to slice a struct array? - arrays

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.

Related

how to check in matlab if a 3D array has at least one non zero element?

I tried to check if a 3D array is not all zeros using the next code:
notAll_n0_GreaterThan_ni=1;
while notAll_n0_GreaterThan_ni
notAll_n0_GreaterThan_ni=0;
mask=(n0<ni);
numDimensions=ndims(mask);
for dim_ind=1:numDimensions
if any(mask,dim_ind)
notAll_n0_GreaterThan_ni=1;
break;
end
end
if notAll_n0_GreaterThan_ni
n0(mask)=n0(mask)+1;
end
end
It seems I have error in the code because at the end I get for example: n_0(11,3,69)=21 while ni(11,3,69)=21.1556.
I can't find the error. I'll appreciate if someone shows me where I'm wrong and also if there is a simpler way to check existence of nonzero elements in a 3D array.
Let x denote an n-dimensional array. To check if it contains at least one non-zero element, just use
any(x(:))
For example:
>> x = zeros(2,3,4);
>> any(x(:))
ans =
0
>> x(1,2,2) = 5;
>> any(x(:))
ans =
1
Other, more exotic possibilities include:
sum(abs(x(:)))>0
and
nnz(x)>0
This is what you looking for
B = any(your_Array_name_here(:) ==0); no need for loops
the (:) turns the elements of your_Array into a single column vector, so you can use this type of statement on an array of any size
I 've tested this and it works
A = rand(3,7,5) * 5;
B = any(A(:) ==0);

Matlab - Slicing an Array without using additional memory

I want to slice an 4D-array into n parts along the 5th Dimension in order to use it in parfor:
X(:,:,:,particles)-->X(:,:,:,particles/n,n)
The Problem is that X is so big that I run out of memory if I start writing it into a new variable, so i want to basically do:
X = cat(5,X(:,:,:,1:particles/n),X(:,:,:,particles/n+1:2*particles/n),...)
I am doing this with
sliced = 'cat(5'
for i=1:n
sliced = strcat(2,sliced,sprintf(',X(:,:,:,(1+(%i-1)*%i):%i*%i)',i,particles/n,i,particles/n))
end
sliced = strcat(2,sliced,')');
X = eval(sliced);
I get:
Error: The input character is not valid in MATLAB statements or expressions.
If i print out the contents of sliced and comment everything and paste the printout of sliced manually into eval('...') it works.
Anyone got a solution for my problem or another way of slicing a 4D array without using additional memory?
Thanks
You can use reshape, which must not use any additional memory -
sz_X = size(X) %// get size
X = reshape(X,sz_X(1),sz_X(2),sz_X(3),sz_X(4)/n,[]); %// reshape and save
%// into same variable and as such must be memory efficient
Ok. I just got things mixed up cat and strcat are not the same... oops :o
n = 4;
particles = 200;
X = rand(6,6,6,particles);
sliced = sprintf('X = cat(5');
for i = 1:n
sliced = cat(2,sliced,sprintf(',X(:,:,:,(1+(%i-1)*%i):%i*%i)',i,particles/n,i,particles/n));
end
sliced = cat(2,sliced,sprintf(');'));
eval(sliced);
works just fine. If somebody has got a better way to slice without memory usage - please feel free to post...

Usage of empty array allocation for custom class

Say, we have a class Car
classdef Car < handle
properties
wheels = 4;
end
methods
function obj = Car()
end
end
end
We can create ten cars like so
cars = Car.empty();
for ii = 1:10
cars(end+1) = Car;
end
However, one can make an empty array of cars first
>> cars = Car.empty(0,10)
cars =
0x10 Car array with properties:
wheels
What I do not understand: If one now puts a single car in it, the array seems to shrink to a single element
>> cars(1) = Car
cars =
Car with properties:
wheels: 4
So, does allocating such an empty array make any sense? What are the use cases?
First of all, note that your question is not directly related to custom classes - you can do this with any MATLAB variable type. For example,
>> a = double.empty(0,10)
a =
Empty matrix: 0-by-10
So your questions are
What I do not understand: If one now puts a single car in it, the array seems to shrink to a single element
Well no, it has grown to a single element. I guess there is an ambiguity here, in that you might expect it to grow not to a 1x1 array but to a 1x10 array, with the other nine elements that weren't directly assigned being set to default (i.e. zero in the case of doubles or other numbers, or to a default element in the case of a custom class). However, I think the only thing to say there is that that's not what MATLAB does.
does allocating such an empty array make any sense? What are the use cases?
The use cases are very few in general, really just edge cases. The capability of having arrays of with zero-length dimensions is obviously required to be there for consistency, but an array of 0x10 is rarely much different in behaviour from an array of 0x0.
If I have an array that may vary in height but will always be 10 wide, I might predefine it as 0x10 rather than 0x0, just to leave myself a reminder in the code of that fact.
Also note that there are differences in behaviour between [] and double.empty(0,0). For example
>> a = rand(4,2)
a =
0.83625 0.19468
0.58508 0.12698
0.44332 0.8509
0.51858 0.3673
>> a(2,:) = []
a =
0.83625 0.19468
0.44332 0.8509
0.51858 0.3673
>> a(2,:) = double.empty(0,0)
Subscripted assignment dimension mismatch.
>> a(2,:) = double.empty(0,2)
Improper assignment with rectangular empty matrix.
This is because = [] is a special piece of MATLAB syntax that is used for deleting rows, rather than literally constructing the empty array and then assigning it. So there's another use case there, i.e. preventing accidental deletion of rows.
This is not a problem related to object programming but a normal behavior which is more general in Matlab.
For instance:
>> a = NaN(0,10);
>> a(1) = 5;
>> a
a =
5
When you define an array of size 0xn Matlab does not allocate any memory to it, since there is no element. So a call to empty(0,10) should not be considered as a pre-allocation.
When you define the first element of the array, you force a resizing, and during resizing Matlab always adopts the minimal possible size for the array.
The empty syntax is useful to define an array that will be filled by aggregation in a loop with the end+1 syntax, for instance:
a = NaN(0,2);
for i = 1:10
a(end+1,:) = [i i^2];
end
Best,

Referencing Structs inside a Cell Array in Matlab

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.

Matlab array of struct : Fast assignment

Is there any way to "vector" assign an array of struct.
Currently I can
edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A.
for i=1:1000000; edges(i).weight=1.0; end;
But that is slow, I want to do something more like
edges(:).weight=[rand(1000000,1)]; //with or without the square brackets.
Any ideas/suggestions to vectorize this assignment, so that it will be faster.
Thanks in advance.
This is much faster than deal or a loop (at least on my system):
N=10000;
edge(N) = struct('weight',1.0); % initialize the array
values = rand(1,N); % set the values as a vector
W = mat2cell(values, 1,ones(1,N)); % convert values to a cell
[edge(:).weight] = W{:};
Using curly braces on the right gives a comma separated value list of all the values in W (i.e. N outputs) and using square braces on the right assigns those N outputs to the N values in edge(:).weight.
You can try using the Matlab function deal, but I found it requires to tweak the input a little (using this question: In Matlab, for a multiple input function, how to use a single input as multiple inputs?), maybe there is something simpler.
n=100000;
edges(n)=struct('weight',1.0);
m=mat2cell(rand(n,1),ones(n,1),1);
[edges(:).weight]=deal(m{:});
Also I found that this is not nearly as fast as the for loop on my computer (~0.35s for deal versus ~0.05s for the loop) presumably because of the call to mat2cell. The difference in speed is reduced if you use this more than once but it stays in favor of the for loop.
You could simply write:
edges = struct('weight', num2cell(rand(1000000,1)));
Is there something requiring you to particularly use a struct in this way?
Consider replacing your array of structs with simply a separate array for each member of the struct.
weights = rand(1, 1000);
If you have a struct member which is an array, you can make an extra dimension:
matrices = rand(3, 3, 1000);
If you just want to keep things neat, you could put these arrays into a struct:
edges.weights = weights;
edges.matrices = matrices;
But if you need to keep an array of structs, I think you can do
[edges.weight] = rand(1, 1000);
The reason that the structs in your example don't get initialized properly is that the syntax you're using only addresses the very last element in the struct array. For a nonexistent array, the rest of them get implicitly filled in with structs that have the default value [] in all their fields.
To make this behavior clear, try doing a short array with clear edges; edges(1:3) = struct('weight',1.0) and looking at each of edges(1), edges(2), and edges(3). The edges(3) element has 1.0 in its weight like you want; the others have [].
The syntax for efficiently initializing an array of structs is one of these.
% Using repmat and full assignment
edges = repmat(struct('weight', 1.0), [1 1000]);
% Using indexing
% NOTE: Only correct if variable is uninitialized!!!
edges(1:1000) = struct('weight', 1.0); % QUESTIONABLE
Note the 1:1000 instead of just 1000 when indexing in to the uninitialized edges array.
There's a problem with the edges(1:1000) form: if edges is already initialized, this syntax will just update the values of selected elements. If edges has more than 1000 elements, the others will be left unchanged, and your code will be buggy. Or if edges is a different type, you could get an error or weird behavior depending on its existing datatype. To be safe, you need to do clear edges before initializing using the indexing syntax. So it's better to just do full assignment with the repmat form.
BUT: Regardless of how you initialize it, an array-of-structs like this is always going to be inherently slow to work with for larger data sets. You can't do real "vectorized" operations on it because your primitive arrays are all broken up in to separate mxArrays inside each struct element. That includes the field assignment in your question – it is not possible to vectorize that. Instead, you should switch a struct-of-arrays like Brian L's answer suggests.
You can use a reverse struct and then do all operations without any errors
like this
x.E(1)=1;
x.E(2)=3;
x.E(2)=8;
x.E(3)=5;
and then the operation like the following
x.E
ans =
3 8 5
or like this
x.E(1:2)=2
x =
E: [2 2 5]
or maybe this
x.E(1:3)=[2,3,4]*5
x =
E: [10 15 20]
It is really faster than for_loop and you do not need other big functions to slow your program.

Resources