Indexing/Accessing MATLAB nested structure - matlab

Hope, that I'm not creating a duplicate, but so far I didn't find the right answer for my problem.
Let's say, we have the following structure(s):
a(1).b = 1;
a(1).x.y = 2;
a(2).b = 3;
a(2).x.y = 4;
When I now try to get all values of b, I can do:
>> a(:).b
ans = 1
ans = 3
But how to this with the nested struct .x.y?
>> a(:).x.y
Expected one output from a curly brace or dot indexing expression, but there were 2 results.
Thanks for your help...!

Just loop over the indices.
>> arrayfun(#(k) a(k).x.y, 1:numel(a))
ans =
2 4
or:
>> struct2array(cell2mat(extractfield(a,'x')))
ans =
2 4

Related

Rearange matlab struct

Lets have a struct defined like this:
s.a = [1, 11];
s.b = [2, 22];
How can I convert it to struct defined like this:
s(1).a = 1;
s(1).b = 2;
s(2).a = 11;
s(2).b = 22;
This need comes from textscan() function. I read large file using this function and then convert the result using cell2struct() function. In this case, however, each field contains whole column, so one has to address individual value by s.column_name(row_index). While I would prefer to do it by s(row_index).column_name.
This type of operation with a struct array does not usually result in pretty code, but here it goes:
s2 = cell2struct(num2cell(cell2mat(struct2cell(s))).', fieldnames(s), 2);
In general, indexing a struct array across its two "dimensions" (fields and array index) is problematic for this reason. Have you considered using a table instead? It allows both types of indexing in a natural way:
s = table; % initiallize as table
s.a = [1; 11]; % note: column vectors
s.b = [2; 22];
So now
>> s
s =
2×2 table
a b
__ __
1 2
11 22
>> s.a
ans =
1
11
>> s.a(2)
ans =
11
>> s(:, 'a') % note: gives a (sub)table
ans =
2×1 table
a
__
1
11
>> s{:, 'a'} % same as s.a
ans =
1
11
>> s{2, :}
ans =
11 22
>> s{2, 'a'} % same as s.a(2)
ans =
11
A possible simple solution would be the following:
fn = fieldnames(s);
for j = 1 : numel(fn)
for k = 1 : numel(s(1).(fn{j}))
s2(k).(fn{j}) = s.(fn{j})(k);
end
end

anonymous function returning updated length of an array - matlab

I'm trying to write a simple anonymous function which returns the length of an array
>> a=[1 2 3];
>> f = #() length(a);
>> f()
3
>> a = [1 2 3 4];
>> f()
3
Is it possible to write a function that returns the length of the updated array every time it's called?
An ugly method to accomplish what you want
global a;
a = [1 2 3];
f = #() eval('global a; length(a)')
f()
a = [1 2 3 4];
f()
I'm compelled to say that I strongly recommend against this type of code as it relies on both globals and calls to eval, both of which should be avoided when possible.
A better method would be to pass in a as an argument to the function
a = [1 2 3];
f = #(x) length(x)
f(a)
a = [1 2 3 4];
f(a)
or, because in this case calling f is identical to calling length, then there's really no reason to use anonymous functions at all.
a = [1 2 3];
length(a)
a = [1 2 3 4];
length(a)
Defining an anonymous function in terms of a variable makes that variable static within the function. i.e.
% this...
a = [1 2 3];
f = #() length(a);
% ... is equivalent to this...
f = #() length([1 2 3]);
You want to create an anonymous function which can take an argument
f = #(x) length(x);
a = [1 2 3];
f(a); % >> ans = 3
a = [1 2 3 4];
f(a); % >> ans = 4
Although at that point, just use length(a) and don't define some pointer-function!

Vectorized or single line evaluation of function array in MATLAB

In a previous question, a user asked about iterating over a cell array of anonymous functions. I am wondering whether there is a way to evaluate a set of functions without the explicit use of a for loop.
As an example, the following code creates an array of (simple) functions, evaluates them for a fixed value and stores the results:
fcnList = {#(x) (x+1), #(x) (x+2)};
a = 2;
for i = 1:numel(fcnList)
y(i) = fcnList{i}(a);
end
Is there a way to do this without looping?
For your example, you could do the following using the cellfun function:
fcnList = {#(x) (x+1), #(x) (x+2)};
a = 2;
cellfun(#(func) func(a),fcnList)
ans =
3 4
Where I have created a handle called func which accepts as input a function from the fcnList variable. Each function is then evaluated for a.
If you need to pass a vector instead of a scalar, for instance b, you will need to set the 'UniformOutput' option to false:
b=[3 4]
fcnList = {#(x) (x+1), #(x) (x+2)};
cellfun(#(func) func(b),fcnList,'UniformOutput',false)
ans =
{
[1,1] =
4 5
[1,2] =
5 6
}
To avoid a for loop or cellfun (which is more or less the same as a loop), you can define a single function with vector output:
fcn = #(x) [x+1, x+2];
Then fcn(a) gives you a vector cointaining the results:
>> fcn = #(x) [x+1, x+2];
>> a = 2;
>> fcn(a)
ans =
3 4
If the results of each original function have different sizes you can define a single function with cell array output:
>> fcn = #(x) {x+1, [x+2; x+3]};
>> a = 2;
>> x = fcn(a)
x =
[3] [2x1 double]
>> celldisp(x)
x{1} =
3
x{2} =
4
5

Selecting an element from a matrix in a cell

Good day,
I have got something similar as:
A = [1 2; 3 4];
B = [2 3; 4 5; 6 7];
C{1} = A;
C{2} = B;
clear A;
clear B;
Now I would like to select element (2,1) from matrix B, that is, element (2,1) from C{2}. However, matrix B itself does not exist any more.
One possibility is:
B = C{2};
B(2,1)
However, is there a more direct way to access elements from matrices which are stored in a cell?
Cells allow you to chain subscripts in the following manner
>> C{2}(2, 1)
ans =
4

Matlab swap

I am trying to create a function that will swap a specific number in a matrix with a specific number in the same matrix. For examlpe, if I start with A = [1 2 3;1 3 2], I want to be able to create B = [2 1 3; 2 3 1], simply by telling matlab to swap the 1's with the 2's. Any advice would be appreciated. Thanks!
If you have the following matrix:
A = [1 2 3; 1 3 2];
and you want all the ones to become twos and the twos to become ones, the following would be the simplest way to do it:
B = A;
B(find(A == 1)) = 2;
B(find(A == 2)) = 1;
EDIT:
As Kenny suggested, this can even be further simplified as:
B = A;
B(A == 1) = 2;
B(A == 2) = 1;
Another way to deal with the original problem is to create a permutation vector indicating to which numbers should the original entries be mapped to. For the example, entries [1 2 3] should be mapped respectively to [2 1 3], so that we can write
A = [1 2 3; 1 3 2];
perm = [2 1 3];
B = perm(A)
(advantage here is that everything is done in one step, and that it also works for operations more complicated than swaps ; drawback is that all elements of A must be positive integers with a known maximum)
Not sure why you would to perform that particular swap (row/column interchanges are more common). Matlab often denotes ':' to represent all of something. Here's how to swap rows and columns:
To swap rows:
A = A([New order of rows,,...], :)
To Swap columns:
A = A(:, [New order of columns,,...])
To change the entire i-th column:
A(:, i) = [New; values; for; i-th; column]
For example, to swap the 2nd and 3rd columns of A = [1 2 3;1 3 2]
A = A(:, [1, 3, 2])
A = [1 2 3; 1 3 2]
alpha = 1;
beta = 2;
indAlpha = (A == alpha);
indBeta = (A == beta);
A(indAlpha) = beta;
A(indBeta ) = alpha
I like this solution, it makes it clearer what is going on. Less magic numbers, could easily be made into a function. Recycles the same matrix if that is important.
I don't have a copy of MatLab installed, but I think you can do some thing like this;
for i=1:length(A)
if (A(i)=1), B(i) = 2, B(i)=A(i)
end
Note, that's only convert 1's to 2's and it looks like you also want to convert 2's to 1's, so you'll need to do a little more work.
There also probably a much more elegant way of doing it given you can do this sort of thing in Matlab
>> A = 1:1:3
A = [1,2,3]
>> B = A * 2
B = [2,4,6]
There might be a swapif primitive you can use, but I haven't used Matlab in a long time, so I'm not sure the best way to do it.
In reference to tarn's more elegant way of swapping values you could use a permutation matrix as follows:
>> a =[1 2 3];
>> T = [1 0 0;
0 0 1;
0 1 0];
>> b = a*T
ans =
1 3 2
but this will swap column 2 and column 3 of the vector (matrix) a; whereas the question asked about swapping the 1's and 2's.
Update
To swap elements of two different values look into the find function
ind = find(a==1);
returns the indices of all the elements with value, 1. Then you can use Mitch's suggestion to change the value of the elements using index arrays. Remeber that find returns the linear index into the matrix; the first element has index 1 and the last element of an nxm matrix has linear index n*m. The linear index is counted down the columns. For example
>> b = [1 3 5;2 4 6];
>> b(3) % same as b(1,2)
ans = 3
>> b(5) % same as b(1,3)
ans = 5
>> b(6) % same as b(2,3)
ans = 6