How do I shorten this code to remove one piece of information from each submatrix?

1 Ansicht (letzte 30 Tage)
I currently have a Matrix (Mcell) made up of 27390 submatrices which are either 2 by 2. or 1 by 1.
For example:
Mcell{1,1} = 8 -0.5
24 -0.6
I need to extract the value 8 (In the 1,1 position) from each of the sub-matrices and have it in a list it doesn't matter if it's a column or a row.
So far I can do this using this code:
A=[Mcell{1,1}(1,1) Mcell{2,1}(1,1) Mcell{3,1}(1,1) Mcell{4,1}(1,1) Mcell{5,1}(1,1)];
But that only works for the first 5, and I need to replicate it for all of them.
I have tried doing the following:
for i= 1:27390;
A=[Mcell{i,1}(1,1)];
end
But it just gave me the 1,1 value for Mcell{27390,1}. Rather than a list of values.
I also need to do this for the {2,1} position of each submatrix but I'm hopeful I can use the same code for both.
It would also need to preserve the length (27390), so where there wasn't a submatrix value for the (2,1) position a '0' needs to go in it's place.
Many thanks
  2 Kommentare
James Tursa
James Tursa am 26 Mai 2016
Bearbeitet: James Tursa am 26 Mai 2016
What does "extract 8" mean? Do you simply mean "extract the (1,1) or (2,1) element of each cell"? For your example above, what would be the desired output?
Olivia Lynes
Olivia Lynes am 26 Mai 2016
The desired output would be 8, from the (1,1) element. I've edited the question so hopefully it makes sense.

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

Guillaume
Guillaume am 26 Mai 2016
Since all your 2D matrices are the same size you might as well all store them as pages of a 3D matrix. This would make your problem easy to solve with simple indexing:
Mmatrix = cat(3, Mcell{:}); %concatenate all matrices along the 3rd dimension
%get element (1, 1) of all matrix:
A = squeeze(Mmatrix(1, 1, :))
The reason your for loop does not work is because you don't do any concatenation in the loop. You just keep on overwriting A all the time. This would work
A = [];
for idx = 1:numel(Mcell) %don't hardcode matrix size when you can simply ask matlab what it is
A = [A, Mcell{idx}(1, 1)];
end
but would be extremely slow due to the constant resizing. This would be slightly faster:
A = zeros(1, numel(Mcell));
for idx = 1 : numel(Mcell)
A(idx) = Mcell{idx}(1, 1);
end
But my first solution is the fastest and most flexible.
  6 Kommentare
Guillaume
Guillaume am 27 Mai 2016
The error occurs because of a mix-up between linear and subscript indexing (which is a bit my fault, sorry).
The if tests that the index is less than the number of elements regardless of the shape of the matrix (I use numel). That in no way guarantee that there are two rows.
So:
A = zeros(1, numel(Mcell)); %preinitialise A full of zeros
rowtoretrieve = 2;
coltoretrieve = 1;
for idx = 1 : numel(Mcell)
if rotoretrieve < = size(mCell{idx}, 1) && coltoretrieve <= size(mCell{idx}, 2)
A(idx) = Mcell{idx}(rowtoretrieve, coltoretrieve);
end
end
Olivia Lynes
Olivia Lynes am 27 Mai 2016
This work's perfectly! Thank you so much. I've been trying to crack this for a while.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (2)

James Tursa
James Tursa am 26 Mai 2016
Bearbeitet: James Tursa am 26 Mai 2016
E.g., to extract the (1,1) element of each cell:
A = cellfun(@(x)x(1,1),Mcell);
For the (2,1) element,
A = cellfun(@(x)x(2,1),Mcell);
etc.
  1 Kommentar
Olivia Lynes
Olivia Lynes am 26 Mai 2016
Thank you, these both work great.
I've just discovered that not all my submatrices have (2,1) elements is there a way to add in a "If there isn't a (2,1) found insert a 0". so I can maintain the length.
Many thanks and sorry for the follow up.

Melden Sie sich an, um zu kommentieren.


Jos (10584)
Jos (10584) am 27 Mai 2016
Bearbeitet: Jos (10584) am 27 Mai 2016
Using an anonymous helper function creating an inline conditional, this is doable with cellfun:
% inline conditional
iif = @(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
% data
MyCell = {[1 2 ; 3 4],[],[10 12],[100 ; 200]}
R = 2 ; C = 1 ;
% get value at (R,C) from each matrix in the cell array.
% If this is not possible, return a NaN
fun = @(M) iif ((R <= size(M,1) && C <= size(M,2)), @() M(R,C), 1, NaN)
X = cellfun(fun , MyCell)
% → X = [3 NaN NaN 100]
  3 Kommentare
Jos (10584)
Jos (10584) am 27 Mai 2016
I fully agree this is obscure! Yet, it does show that branching is possible using function handles. I love matlab for making this kind of code possible :)
Your second statement is not true, as the last two inputs to iif are "true,NaN".
Guillaume
Guillaume am 27 Mai 2016
I would love matlab more if they'd not restricted anonymous functions to not having branching or assignment which would eliminate the need for these workarounds. I understand where that comes from in a pass-by-value world, but still it's woefully underpowered compared to other languages. And since matlab also has to some pass-by-reference (handle classes) blocking assignment does not always make sense.
What I meant is that the syntax of the iif is iif(condition1, action1, condition2, action2, ...). If none of the conditions are true then the function errors. You indeed avoided that problem by forcing the last condition to always be true. However, it's a bit unnexpected to have a to define a elseif true do ... in a branching statement, so it could be easily forgotten.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Matrix Indexing finden Sie in Help Center und File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by