-1

I have a 2D cell-array (A = 2x3) containing numerical vectors of unequal length, in this form:

1x3 1x4 1x2
1x7 1x8 1x3

*Size of A (in both dimensions) can be variable

I want to pad each vector with whitespace {' '} to equalise their lengths to lens = max(max(cellfun('length',A)));- in this case, all vectors will become 1x8 in size - and then subsequently rearrange the cell array into this form so that it can be converted to a columnar table using cell2table (using sample data):

4   1   2   1   3   4
8   5   8   4   7   9
10  12  11  5   []  11
[]  13  21  7   []  []
[]  15  []  11  []  []
[]  18  []  23  []  []
[]  21  []  29  []  []
[]  []  []  32  []  []

[ ] = Whitespace

i.e. columns are in the order A{1,1}, A{2,1}, A{1,2}, A{2,2}, A{1,3} and A{2,3}.

If A = 4x3, the first five columns after the rearrangement would be A{1,1}, A{2,1}, A{3,1}, A{4,1} and A{1,2}.

AnnaSchumann
  • 1,261
  • 10
  • 22

3 Answers3

2

Unfortunately, I don't have time to test this, but I believe this should work if you want to do this fast and simple, without having to write explicit loops.

b = cellfun(@(c) [c, repmat(' ', 1, 197-numel(c))], a,'UniformOutput',0)

Edit:

I don't have MATLAB here, and I have never used table before, so I don't know exactly how it works. But, I assume the easiest way to do this is to use the line above, but instead of trying to pad with spaces, pad it with NaNs. After that, when you have made your table with NaNs, you can do something like:

So:

B = A(:);   % Straighten it out
C = cellfun(@(c) [c, repmat(NaN, 1, 8-numel(c))], B,'UniformOutput',0) % 1x8 vectors

%% Create table %%

tab(tab == NaN) = ' ';

Sorry if this didn't help. It's all I can do at the moment.

Stewie Griffin
  • 14,889
  • 11
  • 39
  • 70
  • I can't figure out the error in this but it is producing jumbles of random characters (see OP EDIT). – AnnaSchumann Sep 03 '15 at 11:28
  • Aaaaah, i didn't notice. A was doubles. When i added `' '` it converted all numbers to chars (with the corresponding number). I'm in a hurry, and on my cell, so I can't answer you, but: you can't pad a numeric array with whitespaces. You have to either convert it to strings, or pad it with something else. I'll update this answer in 8-10 hours if you haven't figured it out by then :-) – Stewie Griffin Sep 03 '15 at 11:40
  • Thanks! I've done something similar before using `cellstr` and `num2str` but I can't seem to figure it out this time. – AnnaSchumann Sep 03 '15 at 13:00
  • Any chance you could update your answer to include a solution to these issues? Unfortunately i've not been able to figure it out. – AnnaSchumann Sep 07 '15 at 13:03
  • @AnnaSchumann, how do you want to pad the array? Do you want to convert all numbers to strings, or do you want to pad it with zeros, NaNs etc.? Can you show it with a 3-by-2 matrix where each vector has sizes 1x3, 1x4. 1x2 etc. Then show what you have, and what you want. =) – Stewie Griffin Sep 07 '15 at 13:03
  • 1
    By the way, that was an insane coincidence. I haven't been on SO for a while and I had written an answer to your comment after 40 seconds... What are the chances I log onto SO 2 seconds after you post a comment? Give me a notice when you have a small example that shows what you want. =) – Stewie Griffin Sep 07 '15 at 13:06
  • Conversion to strings and subsequent padding with whitespace is the ideal solution as I wish to eventually store this in a table and print it (with writetable) to a .txt file with the whitespace included so each column ends at a different length. I'm on my cell myself at the moment so I will update the OP later today with an example input and output if this is not clear. – AnnaSchumann Sep 07 '15 at 13:08
  • Updated the OP to give a more detailed example. Hope it makes sense now! – AnnaSchumann Sep 07 '15 at 15:50
  • Hi @AnnaSchumann. I've updated with all I can... I don't have MATLAB and have never used `table`. I think hope it gets you going. – Stewie Griffin Sep 07 '15 at 20:39
  • Thank you for all your attempts to help =) This was very useful too! – AnnaSchumann Sep 08 '15 at 13:00
2

My version of Matlab (R2013a) does not have cell2table so like Stewie Griffin I'm not sure which exact format you need for the conversion.

I am also not sure if padding vectors of double with whitespace is such a good idea. strings and double are not convenient to be mixed. Specially if in your case you just want cell array columns of homogeneous type (as opposed to column where each element would be a cell). It means you have to:

  • convert your numbers to string first (e.g. char array).
  • since the column will be a char array, they need to be homogeneous in dimension, so you have to find the longest string and make them all the same length.
  • Finally, you can then pad you char array column with the necessary number of whitespace

One way to do that require multiple cellfun calls to probe for all these information we need before we can actually do the padding/reshaping:

%// get the length of the longest vector
Lmax = max(max(cell2mat(cellfun( @numel , A  , 'uni',0)))) ;
%// get the maximum order of magnitude
n = max(max(cell2mat(cellfun( @(x) max(ceil(log10(x))) , A  , 'uni',0)))) 
%// prepare string format based on "n"
fmt = sprintf('%%0%dd',n) ;
%// pad columns with necessary number of whitespace
b = cellfun( @(c) [num2str(c(:),fmt) ; repmat(' ', Lmax-numel(c),n)], A ,'uni',0 ) ;
%// reshape to get final desired result
b = b(:).' 

b = 
    [8x2 char]    [8x2 char]    [8x2 char]    [8x2 char]    [8x2 char]    [8x2 char]

Note that a call to str2num on that would yield your original cell array (almost, less a reshape operation), as str2num will ignore (return empty) the whitespace entries.

>> bf = cellfun( @str2num , b,'un',0 )
bf = 
    [3x1 double]    [7x1 double]    [4x1 double]    [8x1 double]    [2x1 double]    [3x1 double]

If I was dealing with numbers, I would definitely prefer padding with a numeric type (also makes the operation slightly easier). Here's an example padding with 'NaN's:

%// get the length of the longest vector
Lmax = max(max(cell2mat(cellfun( @numel , A  , 'un',0)))) ;
%// pad columns with necessary number of NaN
b = cellfun( @(c) [c(:) ; NaN(Lmax-numel(c),1)], A ,'un',0 ) ;
%// reshape to get final desired result
b = b(:).' 

b = 
    [8x1 double]    [8x1 double]    [8x1 double]    [8x1 double]    [8x1 double]    [8x1 double]

If you do not like operating with NaNs, you could choose a numeric value which is not among the possible values of your dataset. For example if all your values are supposed to be positive integers, -1 is a good indicator of a special value.

%// choose your NULL value indicator
nullNumber = -1 ;
b = cellfun( @(c) [c.' ; zeros(Lmax-numel(c),1)+nullNumber], A ,'un',0 ) ;
b = b(:).' 

cell2mat(b)
ans =
     4     1     2     1     3     4
     8     5     8     4     7     9
    10    12    11     5    -1    11
    -1    13    21     7    -1    -1
    -1    15    -1    11    -1    -1
    -1    18    -1    23    -1    -1
    -1    21    -1    29    -1    -1
    -1    -1    -1    32    -1    -1

Note:

If -1 is a possible value for your set, and you still don't want to use NaN, a value widely used in my industry (which is totally allergic to NaN) as a null indicator for all real numbers is -999.25. Unless you have a very specific application, the probability of getting exactly this value during normal operation is so infinitesimal that it is ok for most software algorithms to recognize a null value when they come across -999.25. (sometimes they use only -999 if they deal with integers only.)

Also note the use of c(:) in the cellfun calls. This makes sure that the vector (in each cell) will be arranged as a column (regardless of it's original shape (because your initial vectors are actually in line as you have them in your example).

Hoki
  • 11,637
  • 1
  • 24
  • 43
  • Very comprehensive answer. – AnnaSchumann Sep 08 '15 at 12:59
  • @AnnaSchumann. Thanks. Any feedback as to which solution is the most useful to send into a `table` ? – Hoki Sep 08 '15 at 13:12
  • The second (padding w. NaN) - however this creates a new problem. Unfortunately, tables do not accept expressions/functions in the same way vectors/cell do - thus trying to replace the NaN with white-space is proving difficult. A table would accept the output of the first solution via `cell2table` however the column formatting was lost and printing this to a .txt file created something basically incomprehensible. – AnnaSchumann Sep 08 '15 at 13:27
1

Padding a vector with a white space:

YourString = 'text here';
YourString = [YourString ' '];

in case only 1 whitespace is required. If more are needed you can loop this code to get the wanted number of spaces attached.

table itself already has the functionality to print cells.

Thanks to @StewieGriffin:

[YourString, repmat(' ',1,197-numel(YourString)]
Adriaan
  • 17,741
  • 7
  • 42
  • 75
  • 1
    Although performance is probably not the main concern here, padding a vector in a loop is a bad idea... It's probably not the best solution, but I would suggest something like: [Yourstring, repmat(' ',1,197-numel(Yourstring)]`. – Stewie Griffin Sep 03 '15 at 10:17