Search code examples
arraysmatlabfor-loopcell-array

Repeating parts of a cell array column in Matlab


I have a cell array with 2 columns in Matlab:

x = {'A', 0
     ' ', 1
     ' ', 1
     'B', 1
     ' ', 0 
     ' ', 1 
     'C', 1
     ' ', 0 
     ' ', 1}

I basically want to write a loop that will look at all the elements of column 1 and if, for example, it finds A then for the next two rows that are '' I want it to label them A as well. Then if it finds B then replace the next two rows with B and then with C... so on...

I tried to use repmat:

for i=1:size(x,1)
      a=repmat({x(i,1),3,1});
end 

I also tried this:

b = {};
for i = 1:size(x,1)
b = {b repmat(x{i,1}, 3, 2)};
end

But I don't get the desired result. Can anyone help?

Thanks


Solution

  • There's a non-loop way you can accomplish this. Note that the following code is generalized to handle any length label or number of spaces (i.e. any all-space entry will be overwritten with the previous label):

    labelIndex = find(~cellfun(@(s) all(isspace(s)), x(:, 1)));
    nRepeats = diff([labelIndex; size(x, 1)+1]);
    x(:, 1) = x(repelem(labelIndex, nRepeats), 1)
    
    x =
    
      9×2 cell array
    
        'A'    [0]
        'A'    [1]
        'A'    [1]
        'B'    [1]
        'B'    [0]
        'B'    [1]
        'C'    [1]
        'C'    [0]
        'C'    [1]
    

    To explain the above... first, find the indices of rows where the first column is not all spaces (using find, cellfun, and isspace). Then, take the differences between these indices (and one past the end of the rows) to get an array of the number of times each label will have to be repeated (using diff). Finally, use repelem to replicate each label the necessary number of times and use the result as an index into the rows of the original array.


    NOTE: The repelem function wasn't introduced until MATLAB version R2015a, so if you have an older version than that you'll have to use one of the solutions from this question for the last step. For example:

    % First two lines same as above...
    clens = cumsum(nRepeats);
    index(clens(end)) = 0;
    index([1; clens(1:end-1)+1]) = diff([0; labelIndex]);
    x(:, 1) = x(cumsum(index), 1);