matrix of objects' array properties - matlab

I have an array of classes (we'll call it a, size Mx1) that contains a property (feature) which holds a 1xN array. I'm trying to get a new matrix that is MxN which contains rows of each of the feature property of the objects. For example:
M = 3
N = 4
a(1,1).feature = [1 2 3 4]
a(2,1).feature = [5 6 7 8]
a(3,1).feature = [9 10 11 12]
then, given some function, the answer would end up as:
ans = [1 2 3 4; 5 6 7 8; 9 10 11 12]
Currently, I've been using the following:
ans = cell2mat({a.feature}')
however I feel there should be a way to do this without having to convert to a cell, switch the dimensions, and then convert to a matrix. Am I correct or would this be the best way to solve the issue? I haven't been able to find any such function in the documentation.

When you have an array of objects and you access a property using dot referencing, a comma separated list is returned. This comma separated list can be passed to a function and will appear as multiple input arguments.
In your case, you can pass this comma separated list to cat and specify that you want each value to be concatenated to the next along the first dimension. So this would simply become:
features = cat(1, a.feature)
%// 1 2 3 4
%// 5 6 7 8
%// 9 10 11 12
This is functionally equivalent to:
features = cat(1, a(1).feature, a(2).feature, a(3).feature, ..., a(end).feature);

Related

visualizing 2D-graphs of n-dim. array via surf() in matlab

I want to show 2dim. Surface plots for different combinations of 2 parameters of a 3- or higher-dimensional array in matlab. The data for the non-shown dimensions are integrated (i.e. summed in the remaining dimensions). I am using surf(), and for parameter combinations other than (1,2) (eg. (1,3), (2,3) ...) I have to rearrange the data matrices in order to make it work.
I am looking for an alternative command (or shorter code) which does this work.
Here's the code:
a=zeros(3,3,2);
a(:,:,1) = [1 2 3 ;4 5 6; 7 8 9; 10 11 12]; % // data matrix
a(:,:,2) = -[1 2 3 ;4 5 6; 7 8 9; 10 11 12]*2; % // data matrix
ai=[[1 2 3 4]' [5 6 7 0]' [8 9 0 0]']; % // parameter vector
mat12 = sum(a,3);
surf(ai(1:3,2),ai(1:4,1),mat12)
aux13 = sum(a,2);
for i = 1:2; mat13(:,i) = aux13(:,:,i);
surf(ai(1:2,3),ai(1:4,1),mat13)
aux23 = sum(a,1);
for i = 1:2; mat23(i,:) = aux23(:,:,i);
surf(ai(1:3,2),ai(1:2,3),mat23)
In other words, I am looking for a way to use surf for matrices mat13 and mat23 without the aux13, aux23 variables and the for loop.
First your example doesn't run because you declare a=zeros(3,3,2); as a matrix [3x3x2] but you immediately try to populate it as a [4x3x2] matrix, so I had to adjust your first line to: a=zeros(4,3,2);
If I run your code with that adjustment, your auxiliary variable and for loops are to reform/reshape a matrix stripped of it's singleton dimension. Matlab provide a handy function for that : squeeze.
For example, your variable aux13 is of dimension [4x1x2], then mat13=squeeze(aux13); achieve the same thing than your for loop. Your matrix mat13 is now of dimension [4x2].
Since no for loop is needed, you can completely bypass your auxiliary variable by calling squeeze directly on the result of your summation: mat13=squeeze( sum(a,2) );
Full example, the code below does exactly the same than your code sample:
mat12 = sum(a,3);
surf(ai(1:3,2),ai(1:4,1),mat12)
mat13 = squeeze( sum(a,2) ) ;
surf(ai(1:2,3),ai(1:4,1),mat13)
mat23 = squeeze( sum(a,1) ) ;
mat23 = mat23.' ; %'// <= note the "transpose" operation here
surf(ai(1:3,2),ai(1:2,3),mat23)
Note that I had to transpose mat23 to make it match the one in your example.
sum(a,1) is [1x3x2] => squeeze that and you obtain a [3x2] matrix but your code arrange the same values in a [2x3] matrix, so the use of the transpose. The transpose operator has a shorthand notation .'.
I used it in the example in a separate line just to highlight it. Once understood you can simply write the full operation in one line:
mat23 = squeeze(sum(a,1)).' ;
The way you write your loops isn't exactly MATLAB syntax. Below is the correct loop syntax shown.
On line 2 and 3, you are trying to load (4x3)-matrices into (3x3)-matrices. That is why you get a subscript error. You could resolve it by making the zeros-matrix bigger. Here's some Syntax fixed:
a=zeros(4,3,2);
a(:,:,1) = [1 2 3 ;4 5 6; 7 8 9; 10 11 12]; % // data matrix
a(:,:,2) = -[1 2 3 ;4 5 6; 7 8 9; 10 11 12]*2; % // data matrix
ai=[[1 2 3 4]' [5 6 7 0]' [8 9 0 0]']; % // parameter vector
mat12 = sum(a,3);
surf(ai(1:3,2),ai(1:4,1),mat12)
aux13 = sum(a,2);
for i = 1:2 mat13(:,i) = aux13(:,:,i);
surf(ai(1:2,3),ai(1:4,1),mat13)
end
aux23 = sum(a,1);
for i = 1:2 mat23(i,:) = aux23(:,:,i);
surf(ai(1:3,2),ai(1:2,3),mat23)
end
Now, what are you exactly trying to do inside those loops?

How to get data from 2D array and put into 1D array

I have a 2D array and I want to create a 1D by MATLAB, satisfying the requirement that each element of the 1D output was created by the value of a given index into the 2D array. Example 2D array is
A=[2 4 6; 1 9 7.3 4 5]
And indexes for the 1D array
X=[1;2;3]
Y=[1;2;3]
I want to store the 1D array with elements determined by
B=A(x,y) % x,y are index in X and Y matrix
Example of building the 1D array:
X=[1;2;3]
Y=[1;2;3]
B=[A(1,1);A(2,2);A(3,3)]=[2; 9; 5]
This is my code
B=zeros(1,length(A));
B=A(...) %I don't know it
How can I implement it?
Thanks all.
You are looking for sub2ind:
A=[2 4 6; 1 9 7; 3 4 5]
X=[1;2;3]; Y=[1;2;3];
B = A(sub2ind(size(A),X,Y))
B =
2
9
5
You can use cellfun to do it. You convert A into cell by column, and execute f for each element of the cell.
A=[2 4 6; 1 2 7];
% some example f funcion that just adds the col_index_A and row_index_A
f = #(col_index_A, row_index_A) col_index_A + row_index_A;
% execute f with parameters that come from each column of A
B = cellfun(#(c) f(c(1), c(2)), num2cell(A, 1));
B =
3 6 13
I am not sure I understand your question but i think you want to apply functions on a 2-by-n matrix
Try
for pos=1:size(a,2)
b(pos) = f(a(:,pos));
end

Extract fixed amounts of data from array based on a list of indices

I have the array
a=1:20
and a series of indices which indicate where I want to start pulling data out:
i=[4,12]
For each index i, I want that index and the next four (well, x, really) elements in a column or row. I'll avoid getting to close to the end of the array, so that special case can be disregarded.
If I was hard-coding this, I could use:
a([4:8;12:16])
and this would achieve my result.
But i may have many different values.
Any thoughts on how I can transform a list of indices into a matrix of ranges, or other ways to solve this problem?
EDIT
I am using Matlab 2007; it would be preferable if the solution relied solely on Matlab's internals and toolboxes. bsxfun is not present until 2007a.
Let i be your indicesx and x the number of elements you want in addition to the elements in i, then you can use
i = [4 6 8];
x = 4;
bsxfun(#plus, 0:x, i(:))
to get a matrix of indices:
ans =
4 5 6 7 8
6 7 8 9 10
8 9 10 11 12
If you do not have access to bsxfun you can use repmat instead:
i = [4 6 8];
x = 4;
repmat(i(:), 1, x+1) + repmat(0:x, length(i), 1)
Here is a solution without bsxfun but with repmat inspired by the previous answer.
i = [4 6 8];
x = 4;
p = repmat(1:x,length(i),1);
q = repmat(i',1,x);
p+q

splitting a Matrix into column vectors and storing it in an array

My question has two parts:
Split a given matrix into its columns
These columns should be stored into an array
eg,
A = [1 3 5
3 5 7
4 5 7
6 8 9]
Now, I know the solution to the first part:
the columns are obtained via
tempCol = A(:,iter), where iter = 1:end
Regarding the second part of the problem, I would like to have (something like this, maybe a different indexing into arraySplit array), but one full column of A should be stored at a single index in splitArray:
arraySplit(1) = A(:,1)
arraySplit(2) = A(:,2)
and so on...
for the example matrix A,
arraySplit(1) should give me [ 1 3 4 6 ]'
arraySplit(2) should give me [ 3 5 5 8 ]'
I am getting the following error, when i try to assign the column vector to my array.
In an assignment A(I) = B, the number of elements in B and I must be the same.
I am doing the allocation and access of arraySplit wrongly, please help me out ...
Really it sounds like A is alread what you want--I can't imagine a scenario where you gain anything by splitting them up. But if you do, then your best bet is likely a cell array, ie.
C = cell(1,3);
for i=1:3
C{i} = A(:,i);
end
Edit: See #EitanT's comment below for a more elegant way to do this. Also accessing the vector uses the same syntax as setting it, e.g. v = C{2}; will put the second column of A into v.
In a Matlab array, each element must have the same type. In most cases, that is a float type. An your example A(:, 1) is a 4 by 1 array. If you assign it to, say, B(:, 2) then B(:, 1) must also be a 4 by 1 array.
One common error that may be biting you is that a 4 by 1 array and a 1 by 4 array are not the same thing. One is a column vector and one is a row vector. Try transposing A(:, 1) to get a 1 by 4 row array.
You could try something like the following:
A = [1 3 5;
3 5 7;
4 5 7;
6 8 9]
arraySplit = zeros(4,1,3);
for i =1:3
arraySplit(:,:,i) = A(:,i);
end
and then call arraySplit(:,:,1) to get the first vector, but that seems to be an unnecessary step, since you can readily do that by accessing the exact same values as A(:,1).

Caching result of pre-computed function in Matlab

I have two arrays, x and y. x is the input of the function and y is the function values.
For example, x = [ 1 2 3 4 5 6 7 8 9 10], y = [ 3 6 2 4 1 6 7 0 1 8 ]. Both are the same length.
Suppose I have an another array z containing [ 2 3 8 9 10 3] (not the same length as x and y),
Is there any functions that produce the output [6 2 0 1 8 2] (return value at corresponding indices) without using for-loop through each element of array?
Thank you so much
edit1* How can I do if the numbers in the arrays are not integer?
y(z)
That's all you need......
I think that you just want:
y(z);
This will return the z'th elements of the y vector. You may want
y(x(z));
Which will return the same result in your example, since x is just the value 1 through 10.
With both of these z can contain only positive integers, and in the second case x must also contain only positive integers.
If you are using a MATLAB version newer than 2008b, you can use the containers.Map class to do what you want, even with non-integer, non-consecutive or non-numeric values:
x = [ 1 2 3 4 5 6 7 8 9 10];
y = [ 3 6 2 4 1 6 7 0 1 8 ];
z = [ 2 3 8 9 10 3];
F = containers.Map(x,y);
% for a single element:
Fz1 = F(z(1))
% for multiple elements at the same time, you need to use arrayfun
Fz = arrayfun(#(x)(F(x)),z)
The Map class actually creates a so-called hashmap, so you can map almost any value to other values (e.g. strings, cells, array, ...).
When the item is not present, it will return an error.
If you cannot use MATLAB 2008b or newer, there are three possibilities for non-integer domain values.
Use an interpolation method such as interp1. That might give false values (at values that weren't provided beforehand). You can check for that case by using ismember(z, x).
Secondly, you could invent your own scheme from non-integers to integers (e.g. if all your values are multiples of 0.5, multiply by 2) and use the solution Oli has shown.
The other solution is to use structs to mimic the behavior of a map. Then you only need a conversion from your domain values to valid field names (i.e. strings that are valid variable names in MATLAB, that may be possible by using the genvarname function).
These last two solutions are somewhat dirty and prone to errors if you don't take rounding into consideration. So I see them only as a last resort.