How to order values within a cell array more efficiently??

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 件のコメント

Ben Petschel
Ben Petschel 2013 年 11 月 15 日
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
Antonio Espana 2013 年 11 月 15 日
Hi Ben thanks for the heads up, you are right the result i wrote is completely wrong and your result is the right one. It is not a problem with the code but a blunder on my side cause i wrote the result of a different ratings array.

サインインしてコメントする。

 採用された回答

Ben Petschel
Ben Petschel 2013 年 11 月 15 日

2 投票

The following should work regardless of the ordering of the two rows:
[~,idx] = ismember(ratings(1,:),ratings(2,:));
orderedratings = ratings(3,idx)

1 件のコメント

Antonio Espana
Antonio Espana 2013 年 11 月 15 日
Hi Ben
Also tested this code and is very fast and elegant, with all this ideas i can get rid of a lot of conditionals thanks.
Antonio

サインインしてコメントする。

その他の回答 (3 件)

Simon
Simon 2013 年 11 月 14 日

1 投票

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 件のコメント

Antonio Espana
Antonio Espana 2013 年 11 月 14 日
Wow.. nice one thanks, a little cluttered but nice, i will test it further and time it...
Simon
Simon 2013 年 11 月 14 日
Yes, it's kind of obfuscated coding, but if you comment your code extensively, there shouldn't be a problem.
Antonio Espana
Antonio Espana 2013 年 11 月 15 日
Hi
Tested it and timed it and is indeed faster, and i am wondering why the results are in double format, is it because it applies the strcmp function to individual cells? (might be the reason is not as fast as the other codes)
Antonio
Simon
Simon 2013 年 11 月 15 日
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
Antonio Espana 2013 年 11 月 15 日
Hi
Thanks for the enlightenment, it does write down a cell array. Now and i am trying to figure out why the
orderedratings{1,7} is a 1x2 cell and orderedratings{1,8} is an empty cell
still the order is correct.
Greetings
Simon
Simon 2013 年 11 月 15 日
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
Antonio Espana 2013 年 11 月 15 日
Thank you very much i overlooked the fact that your example had two cells with the same value whereas my normal ratings arrays never have repeated values. Now, that could be useful way to control my arrays hehe.
Antonio

サインインしてコメントする。

Azzi Abdelmalek
Azzi Abdelmalek 2013 年 11 月 14 日
編集済み: Azzi Abdelmalek 2013 年 11 月 15 日

1 投票

[~,~,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 件のコメント

Simon
Simon 2013 年 11 月 15 日
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
Antonio Espana 2013 年 11 月 15 日
編集済み: Antonio Espana 2013 年 11 月 15 日
Hi Azzi
Thanks for the contribution, i have been testing your code and it works as i desire (also the fastest of them all). But is a little bit confusing to me how does it sorts the third row correctly without having to consider the second row, but i will give it more thought.
Azzi Abdelmalek
Azzi Abdelmalek 2013 年 11 月 15 日
Because your second row is already sorted, if not, this code does not work, like mentioned by Simon
Azzi Abdelmalek
Azzi Abdelmalek 2013 年 11 月 15 日
Look at ADD in case the second row is not sorted
Antonio Espana
Antonio Espana 2013 年 11 月 15 日
Silly me now i get what you mean by sorted, my second row is always sorted because is the result of another implementation of the unique function in another part of my code, i scrambled the second row a bit and with the ADD code still manages to work. Thanks
Antonio

サインインしてコメントする。

Azzi Abdelmalek
Azzi Abdelmalek 2013 年 11 月 15 日

1 投票

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 件のコメント

Antonio Espana
Antonio Espana 2013 年 11 月 15 日
Thanks
Still the fastest one, although with more lines of code, i will need to read the manual of sort to understand it, thank you.
Antonio
Azzi Abdelmalek
Azzi Abdelmalek 2013 年 11 月 15 日
After speed test, this code seems slightly faster then my previous answer
Antonio Espana
Antonio Espana 2013 年 11 月 15 日
it is indeed :-)

サインインしてコメントする。

カテゴリ

ヘルプ センター および File ExchangeCreating and Concatenating Matrices についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by