Access predefined elements of cells - matlab

I have a cell array A [1x80] in which each element is a cell array itself [9x2].
I have also a vector B representing a group of selected cells of A and I want to extract the element {2,2} of each selected cell.
I tried with a simple
A(1,B){2,2}
but of course it doesn't work....
Can you help me?

How about this:
A = {{1 2; 3 4}, {5 6;7 8}, {9 0; 1 2}; {3 4; 5 6}, {7 8; 9 0}, {11 22; 33 44}};
B = [2,3]
[cellfun(#(x)x(2,2), A){1, B}]
ans =
8 2
EDIT:
The above actually only works in octave. As #Amro points out, to modify it to work in Matlab you need to use a temporary variable:
temp = cellfun(#(x)x(2,2), A);
[temp{1, B}]
or in a one liner (also thanks to #Amro)
cellfun(#(c)c{2,2}, A(1,B))

This answer is the same as #Dan's, but using a simple for loop for performance improvement, if needed.
% If you know that the numel of elements returned by {2,2} will always be one:
nElem = numel(B);
ret(1,nElem)=0;
for k=1:nElem
ret(k) = A{1,B(k)}{2,2}
end
The following answer is wrong, it will only return the {2,2} index from the first element from B
subsref([A{1,B}],struct('type','{}','subs',{{2,2}}))
Which sounds more like what you are doing (and doesn't uses cellfun and arrayfun, that would be better if you are doing this operation on a loop, because they are slow)
See subsref documentation here.
A longer path would be:
temp = [A{1,B}]
temp{2,2}

How about arrayfun(#(x) A{1,x}{2,2}, B)
or (thanks #Amro) cellfun(#(c)c{2,2}, A(1,B))?

Related

How would i vectorize that 'for' loop in Matlab?

I have this toy example:
l = [1, 2, 3, 4, 5];
a = zeros(3, 1);
for p = 1:3
a(p) = sum(l(p:p+2));
end;
This example calculates sum of each 3 elements in 'l', which are close to each other and writes it in 'a'. Now, is it possible to rewrite the same code using vectorization and matrix operations, without 'for' loop? I have tried something similar to:
p = 1:3;
a(p) = sum(l(p:p+2));
The result was [6, 6, 6], it have calculated sum of the first three elements and wrote it in 'a' on each position. This is only a toy example, but i need to do something similar on 3d 256x256x128 array with 20x20x20 cube elements sum, using 'for' loops was VERY slow there. So, is there a fast way to solve this problem?
Edit :
Divakar have suggested me to use my actual case here. Well, here is the most important part of it, which i am trying to rewrite:
Edit2 :
Thank you for answer. Understood the idea, removed code above, rewriting it now.
You're describing a basic convolution:
a = conv(l,ones(1,3),'valid'); % a should have 3 elements
For 3d, use convn in a similar fashion with ones(20,20,20)

Compare an array to several numbers at once

How do you compare an array of numbers to several given numbers? More precisely, I have an array given like so
inputArray = [1 2 2 3 4 6]
and I want to compare inputArray to the numbers 1:7 to ultimately count how many times a "1" is in inputArray, a "2", a "3" and so on.
Obviously I can do something like
res = zeros(7,1);
for i = 1:7
res(i) = sum(inputArray == i);
end
or more generally when I also might be interested in the locations of occurrences
res = zeros(7,length(inputArray));
for i = 1:7
res(i,:) = inputArray == i;
end
res2 = sum(res,1);
Out of curiosity and/or speed improvements I am wondering if this is possible without a for loop in a single statement?
It seems like you are looking for a histogram count, see here:
x = [1 3 10 1 8]
b = [1 2 3]
histc(x,b)
Will produce
[2 0 1]
Yet another possibility: use accumarray:
count = accumarray(inputArray(:), 1, [7 1]); %// Change "7" as needed
When you want more dimensions of vectorization than is built in to the functions you're working with, or want to collapse a simple loop into a function call, you can use bsxfun ("Binary Singleton eXpansion FUNction"). It's pretty general, reasonably fast, and produces concise code.
In this case, you could use it to construct that equality grid, and then sum them up.
a = [1 2 2 3 4 5];
i = [1:7]'; % Flip it so it's oriented perpendicular to a
res = bsxfun(#eq, a, i);
counts = sum(res,2)'; %'
% One-liner version
counts = sum(bsxfun(#eq, a, [1:7]'), 2)';
Though in the particular case you're working with, since you're doing simple arithmetic operations on primitive arrays, the for loops might actually be fastest with JIT optimizations, as long as you're careful to isolate the work in its own function so the JIT can do "in-place" optimizations.

Make vectors of unequal length equal in length by reducing the size of the largest ones

I am reading 5 columns from a .txt file to 5 vectors.
Sometimes some vectors are one element larger than others, so I need to check if they are all of equal length, and if not, I have to find which ones are the largest and delete their last element. I think I should be able to do this without loops. I was originally thinking of using find in combination with isequal but isequal only returns a logical, and does not provide any information on which vectors are the largest.
[Seconds,Sensor1VStatic,Sensor2VPulsed,TemperatureC,RelativeHumidity] = importfile(path);
Then depending on what vectors are longer by one element, I will do, for example
Seconds(end) = [];
Sensor1VStatic(end) = [];
If Seconds and Sensor1VStatic are longer than the other vectors by one element
Assume your vectors are in a cell array A:
A = {[1 2 3], [1 2 3 4], [1 2 3 4 5]};
You can get the size of each vector with
sz = cellfun(#(x)size(x,2), A);
Which will return (for the above example)
sz = [ 3 4 5]
Now you can find the shortest vector:
minLength = min(sz);
And finally, make all vectors this length:
B = cell2mat(cellfun(#(x)x(1:minLength), A, 'uniformoutput', false))';
There may be more elegant ways (and note that cellfun really is doing "implicit looping")
Applying this to your (now expanded) example, you could probably assign the output of importfile directly to the cell array - or you can do it as a separate line:
A = {Seconds,Sensor1VStatic,Sensor2VPulsed,TemperatureC,RelativeHumidity};
But it all becomes a lot of work. Instead you could do:
minLength = min(size(Seconds,1), size(Sensor1VStatic,1), size(Sensor2VPulsed,1), ...
Seconds = Seconds(1:minLength);
...
There is scope for some cleverness but it won't make things more readable, and it won't save time in the long run...

Find the elements in an array that is not in another array

I have two arrays lets say A = [1;2;4;7;10;20];
B = [1;4;8];
Now I want to find the elements of A, that are not in B i.e; [2;7;10;20]. I just need their index that is the index of the elements [2;7;10;20] in A. How can I implement this in matlab. I can use loops and all. But that is not what I want. I want an elegant solution. Suggestions?
You can do that using the ismember function.
A = [1;2;4;7;10;20];
B = [1;4;8];
ismem = ismember(A,B);
will give you
[1 0 1 0 0 0]'
If you really need the indices, you can use find.
find(ismem==0)
Just as a reminder, you can always use logical indexing like so:
A(~ismem)
will give you
[2 7 10 20]'
If you want the elements of A which are not in B you can use setdiff.
If you want the indices of the elements rather than their values, you can use ismember and negate the result.
Check out setxor:
[C, ia, ib] = setxor(A, B)
Here is the Mathworks page. You will want ia for the indexes of those that are in A but not B.

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).