1

I am limited in the use of cycles in matlab and I have one task. I have the matrix 2xn with numbers and cell array 1xn. Each element in the first row point to a position of the array. I want to add every number from the second row of matrix to cell, which is pointed by corresponding number in the first row. In addition, I want the cells to be strings.

Let me clarify with example:

A = [[1 4 3 3 1 4 2], [7 4 3 5 6 5 4]]

I want to get array of cells: {'76', '4', '35', '45'}

How can I do this without using a for or while loop?

Macaronnos
  • 647
  • 5
  • 14

2 Answers2

4
A = [1 4 3 3 1 4 2; 7 4 3 5 6 5 4]; %// data: 2 x n array
[~, ~, ii] = unique(A(1,:));
R = accumarray(ii(:),A(2,:),[],@(v) {fliplr(regexprep(num2str(v(:).'),'\s',''))}).';

The second line (unique) is used to remove possible gaps in first row. Otherwise those gaps would translate to the result of accumarray, which would then take up more memory uselessly.

The third line (accumarray) aggregates all values of second row of A that have the same value in the first row. The aggregation is done by the anonymous function, which converts numbers to string (num2str), removes spaces (regexprep), and changes orientation (fliplr and .') to match the desired output format.

EDIT:

Thanks to @chappjc's suggestion, the third line can be simplified to

R = accumarray(ii(:),A(2,:),[],@(v) {fliplr(num2str(v(:).','%d'))}).';
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • how do you come up with such complicated expressions :P? – Autonomous Mar 10 '14 at 17:01
  • @Parag :-) I've added some explanations – Luis Mendo Mar 10 '14 at 17:06
  • Its not about how complicated it is... its about how fast you came up with it :). – Autonomous Mar 10 '14 at 17:09
  • 1
    You can do without `regexprep` because `num2str` has a format specifier, which does not produce spaces: `num2str([7 6],'%d')`. Or you could use `sprintf('%d',[7 6])` – chappjc Mar 10 '14 at 17:34
  • @chappjc Nice! Those spaces were annoying. BTW, I just found out (working in this answer) that `accumarray` can return cells, which makes it even more powerful! – Luis Mendo Mar 10 '14 at 17:47
  • 1
    I think you just [forgot](http://stackoverflow.com/a/17775147/2778484)! :) But, agreed, it does open lots of fun doors! – chappjc Mar 10 '14 at 18:03
  • @chappjc Hey, you're right! I don't even remenber having seen some of the comments in that Q&A (Was it really me who answered??) – Luis Mendo Mar 10 '14 at 22:32
2

Alright, by just pointing at cellfun, arrayfun, cell2mat, cell indexing and array indexing I was arrogant. So, I try to make it up by actually using some of those in a more constructive solution:

%// Using array-indexing to find all matches with the current index in the first row, 
%// then print their counterpart(s) into strings
fun = @(ii) sprintf('%d', A(2, A(1, :) == ii));  
%// The following could also be 1:size(A, 2) or unique(A(1, :)) depending on the 
%// general form of your problem.
range = min(A(1, :)) : max(A(1, :));   
%// Using arrayfun to loop over all values in the first row
R = arrayfun(fun, range, 'UniformOutput', false)
mbschenkel
  • 1,865
  • 1
  • 18
  • 40