Search code examples
arraysoctavecell-array

Cannot fill cell array with mixed string/numeric data


I am trying to fill an empty cell array with mixed numeric and string data to subsequently write to Excel and have come up with a problem. The following MCVE should reproduce the issue:

First, I create the cell array and set the top left element to an empty string. So far so good:

xls_array = cell(7,6);
xls_array{1,1} = '';

Then I need to populate the first line and the first column of the array with their respective headers. These are variables (cell arrays) created elsewhere in the code, but for the purpose of the MCVE, I have created some artificial ones:

col_headers = {'Channel 1';'Channel 2';'Channel 3';'Channel 4';'Channel 5'};
xls_array(1,2:end) = col_headers';
row_headers = {'Var A';'Var B';'Var C';'Var D';'Var E';'Var F'};
xls_array(2:end,1) = row_headers;

So far, so good. Now I need to add the actual data to the cell array and that's where the problem arises. Again, for the purpose of the MCVE, I have generated some random data:

data = rand(6,5);
xls_array{2:end,2:end} = data;

This gives me the following error message:

>> xls_array{2:end,2:end} = data;
error: invalid dot name structure assignment because the structure array is empty.  Specify a subscript on the structure array to resolve.

If I try normal brackets instead of curly brackets, it doesn't error out but doesn't give me the expected result either:

xls_array(2:end,2:end) = data;
>> xls_array{2,2}
ans =

   0.326180   0.169640   0.381373   0.416490   0.283456
   0.350000   0.366084   0.409047   0.619715   0.962095
   0.526219   0.466591   0.553932   0.930187   0.460585
   0.983679   0.324129   0.964619   0.080852   0.786360
   0.069995   0.835966   0.266789   0.673177   0.796602
   0.741368   0.233794   0.022568   0.012975   0.248514

i.e. it has copied the entire numeric array data in each element of the cell array xls_array(2:end,2:end).

What I want instead is to copy data into the remaining blank cells of the cell array, i.e. data(1,1) should be in xls_array{2,2}, data(1,2) in xls_array{2,3}, etc...

I have also tried the following, to no avail:

>> xls_array{2:end,2:end}(:) = data;
error: a cs-list cannot be further indexed

Can anybody help?


Solution

  • You need to convert the numeric array to a cell array and use parentheses for indexing:

    xls_array(2:end,2:end) = num2cell(data);
    

    Curly brackets can be used this way:

    [xls_array{2:end,2:end}] = num2cell(data){:};
    

    Alternatively you can use the concatenation operator to create the result:

    xls_array = [{''}, col_headers.'; row_headers, num2cell(data)];
    

    Why other methods don't work?

    Curly brackets are used for a special type of indexing which returns the contents of a cell array as a comma separated list . If the LHS is a comma separated list the RHS should be also be a comma separated list that the number of its elements isn't less than the that of LHS and square brackets should be used around the LHS. More about comma separated lists can be found in the documentation. So xls_array{2:end,2:end} = data; is wrong because data can be interpreted as a comma separates list containing only one element but the LHS requires more elements and also the square brackets are missing.

    The example xls_array(2:end,2:end) = data; I think is a bug in Octave because a cell array is an array that the type of its elements is cell. When parentheses are used for normal cell indexed assignment, the right hand side of the assignment should be of type cell and there is no implicit conversion form other types to cell type. So xls_array(2:end,2:end) = data; should be wrong because data is of double type. However we can see that the behavior of Octave is that data is implicitly converted to a cell {data} and then assigned to elements of LHS.