textscan() reading result is a nested cell array?

2019-09-18 09:36发布

问题:

I have a data file containing 100 lines with the following format

0,device1,3
1,device2,33
2,device3,3
3,device4,34
...
99,device100,36

Now I wish to read them into a 100x3 cell array in MATLAB. I did the following:

allData = textscan(fID,'%s %s %f', 'delimiter', ',');

Then, I noticed that allData is a 1x3 cell array with each item being another 100x1 cell array. (The first two columns are string-type cell arrays, whereas the third column is double-type cell array)

In other words, the reading result is a nested array, which I don't want.

How may I achieve 100x3 cell array directly while reading?

回答1:

With that textscan, the variable allData looks something like (just 4 rows) this:

allData = 
    {4x1 cell}    {4x1 cell}    [4x1 double]

You can only merge into a single cell array directly with textscan via the 'CollectOutput' option when all data has the same type.

One possible workaround, which unfortunately converts all numeric data to double (not a problem in your case),

C = cell(numel(allData{1}),numel(allData));
areCells = cellfun(@iscell,allData);
C(:,areCells) = [allData{areCells}];
C(:,~areCells) = num2cell([allData{~areCells}])
C = 
    '0'    'device1'    [ 3]
    '1'    'device2'    [33]
    '2'    'device3'    [ 3]
    '3'    'device4'    [34]

Again, the drawback of this is that the last statement will convert all non-cell types (e.g. uint8, char, etc.) into doubles. To avoid this possible conversion:

% after copying cell array data (areCells) as above, but before ~areCells data
Cn = arrayfun(@(ii)num2cell(allData{ii}),find(~areCells),'uni',0);
C(:,~areCells) = [Cn{:}];


回答2:

Code -

sz = 100;                         % Line count
out=cell(sz,size(allData,2));             
for k = 1:size(allData,2)
    t1 = allData(k);
    t2 = [t1{:}];
    if isnumeric(t2)              % Takes care of floats
        out(:,k) = num2cell(t2);
    else
        out(:,k) = t2
    end
end

Thus, the first four lines would be shown as -

out = 

    '0'    'device1'    [ 3]
    '1'    'device2'    [33]
    '2'    'device3'    [ 3]
    '3'    'device4'    [34]