How to order values within a cell array more efficiently??
Mostrar comentarios más antiguos
I have a 3x12 cell array called "ratings"
ratings= {'AAA','AA','A','A-','BBB-','BB+','BB','BB-','B+','B','B-','CCC+';
'A','A-','AA','AAA','B','B+','B-','BB','BB+','BB-','BBB-','CCC+';
1,1,1,3,11,16,18,1,1,17,16,14};
- The first row of the array has the ratings in the desired order
- The second row has the ratings disordered
- The third row contains a number associated with the ratings in the second row
I wrote the following code:
orderedratings=cell(1,length(ratings))
for i=1:length(ratings);
for j=1:length(ratings)
if strcmp(ratings(1,i),ratings(2,j))==1
orderedratings(i)=ratings(3,j);
end
end
end
and it allows me to reorder the third row in respect to the ordered first row, such that:
orderedratings={1,6,8,2,18,3,1,21,17,12,10,1}
Is there a way to do the same more efficiently, or another way without "for" conditionals?? It is very much appreciated a different appoach.
Antonio Espana
2 comentarios
Ben Petschel
el 15 de Nov. de 2013
If I run your code I get a different result:
orderedratings = { 3, 1, 1, 1, 16, 1, 1, 17, 16, 11, 18, 14}
Not sure how you obtained {1,6,8,...}
Antonio Espana
el 15 de Nov. de 2013
Respuesta aceptada
Más respuestas (3)
Simon
el 14 de Nov. de 2013
Hi!
orderedratings = cellfun(@(x) ratings{3,x}, ...
cellfun(@(x) strcmp(x,ratings(2,:)), ratings(1,:), 'UniformOutput', false));
It takes about 2/3 of the time, but it is not very easy to read ...
7 comentarios
Antonio Espana
el 14 de Nov. de 2013
Simon
el 14 de Nov. de 2013
Yes, it's kind of obfuscated coding, but if you comment your code extensively, there shouldn't be a problem.
Antonio Espana
el 15 de Nov. de 2013
Simon
el 15 de Nov. de 2013
Hi!
Using cellfun is a replacement for a loop, but it is not always fast.
The result is in double because the first line has "ratings{3,x}" instead of "ratings(3,x)". In this case it is possible because you have unique entries in the second row of your cell array "ratings" and the same entries as in the first row. Otherwise the second cellfun call might give problems if e.g. no match is found for an entry of the first row inside the second row. Try with
ratings= {'AAA','AA','A','A-','BBB-','BB+','BB','BB-','B+','B','B-','CCC+';
'A','A-','AA','AAA','B','B+','B-','BB','BB+','BB','BBB-','CCC+';
1,1,1,3,11,16,18,1,1,17,16,14};
% error, no result
orderedratings = cellfun(@(x) ratings{3,x}, cellfun(@(x) strcmp(x,ratings(2,:)), ratings(1,:), 'UniformOutput', false), 'UniformOutput', false);
% no error, result as cell array
orderedratings = cellfun(@(x) ratings(3,x), cellfun(@(x) strcmp(x,ratings(2,:)), ratings(1,:), 'UniformOutput', false), 'UniformOutput', false);
Antonio Espana
el 15 de Nov. de 2013
Simon
el 15 de Nov. de 2013
orderedratings{1,7} is a 1x2 cell because the 7th element in the first row of ratings 'BB' is found in the 8th and 10th element of the second row, while the 8th element in the first row of ratings 'BB-' wasn't found at all in the second row. Great, isn't it? ;-)
Antonio Espana
el 15 de Nov. de 2013
Azzi Abdelmalek
el 14 de Nov. de 2013
Editada: Azzi Abdelmalek
el 15 de Nov. de 2013
[~,~,idx]=unique(ratings(1,:));
out=ratings(3,idx)
ADD
If the second row is not sorted
[idx2,idx2]=sort(ratings(2,:));
[~,~,idx12]=unique(ratings(1,:));
idx12=idx2(idx12);
out=ratings(3,idx12);
5 comentarios
Simon
el 15 de Nov. de 2013
Hi!
I think this works in this case because the second row is the result of sorting the first row. I'm not sure if this is always the case for Antonio. If so it's a nice and fast solution.
Antonio Espana
el 15 de Nov. de 2013
Editada: Antonio Espana
el 15 de Nov. de 2013
Azzi Abdelmalek
el 15 de Nov. de 2013
Because your second row is already sorted, if not, this code does not work, like mentioned by Simon
Azzi Abdelmalek
el 15 de Nov. de 2013
Look at ADD in case the second row is not sorted
Antonio Espana
el 15 de Nov. de 2013
Azzi Abdelmalek
el 15 de Nov. de 2013
In case the second row is not sorted
[idx1,idx1]=sort(ratings(1,:));
[idx2,idx2]=sort(ratings(2,:));
[kk,kk]=sort(idx2);
[idx,idx]=sort(idx1(kk));
orderedratings = ratings(3,idx);%
3 comentarios
Antonio Espana
el 15 de Nov. de 2013
Azzi Abdelmalek
el 15 de Nov. de 2013
After speed test, this code seems slightly faster then my previous answer
Antonio Espana
el 15 de Nov. de 2013
Categorías
Más información sobre Creating and Concatenating Matrices en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!