gusucode.com > bigdata 工具箱 matlab源码程序 > bigdata/+matlab/+bigdata/+internal/+adaptors/combineAdaptors.m

    function out = combineAdaptors(dim, inCell)
%combineAdaptors Combination of adaptors for horizontal concatenation

% Copyright 2016 The MathWorks, Inc.

adaptorClasses = cellfun(@class, inCell, 'UniformOutput', false);

underlyingClasses = cellfun(@(x) x.Class, inCell, 'UniformOutput', false);
isKnownUniqueUnderlyingClass = numel(unique(underlyingClasses)) == 1 && ...
    ~isempty(underlyingClasses{1});

% Allowed combinations:
% - all 'generic' adaptors, return a plain generic adaptor
% - all DatetimeFamilyAdaptor
%   - if classes all match
%   - or duration + calendarDuration -> calendarDuration
% - datetime and char/string -> datetime
% - duration|calendarDuration and numeric -> duration|calendarDuration
% - all TableAdaptor - concatenate VariableNames and Adaptors providing VariableNames unique
% - categorical will need special handling when it becomes a "strong" type.
% - if 'string' were to become a "strong" type, more special handling needed.

if all(strcmp(adaptorClasses, 'matlab.bigdata.internal.adaptors.GenericAdaptor'))
    out = matlab.bigdata.internal.adaptors.GenericAdaptor();
    if isKnownUniqueUnderlyingClass
        out = matlab.bigdata.internal.adaptors.getAdaptorForType(underlyingClasses{1});
    end
elseif any(strcmp(adaptorClasses, 'matlab.bigdata.internal.adaptors.DatetimeFamilyAdaptor'))
    
    % Here we still consider unknown (empty) classes
    uc = unique(underlyingClasses);
    if numel(uc) == 1
        out = matlab.bigdata.internal.adaptors.DatetimeFamilyAdaptor(underlyingClasses{1});
    else
        % We need to work out from the known-good combinations of classes. Disregard
        % unknown classes for now, treat them as if they'll work, and hope for
        % the best.
        uc(isempty(uc)) = [];
        if isempty(setdiff(uc, { 'datetime', 'char', 'string', 'cell' }))
            outClass = 'datetime';
        elseif isempty(setdiff(uc, { 'duration', 'double', 'logical' }))
            outClass = 'duration';
        elseif isempty(setdiff(uc, { 'duration', 'calendarDuration', 'double', 'logical' }))
            outClass = 'calendarDuration';
        else
            error(message('MATLAB:bigdata:array:InvalidConcatenation', strjoin(uc, ' ')));
        end
        out = matlab.bigdata.internal.adaptors.DatetimeFamilyAdaptor(outClass);
    end
elseif all(strcmp(adaptorClasses, 'matlab.bigdata.internal.adaptors.TableAdaptor'))
    allVarNames = cellfun(@(x) x.VariableNames, inCell, 'UniformOutput', false);
    allVarNames = [allVarNames{:}];
    
    [uniqueVarNames, ~, ic] = unique(allVarNames);
    if numel(allVarNames) ~= numel(uniqueVarNames)
        % find first duplicate, and error as per table/cat ...
        occurenceCount = accumarray(ic, 1);
        firstNonUnique = find(occurenceCount > 1, 1, 'first');
        assert(isscalar(firstNonUnique));
        firstNonUniqueName = uniqueVarNames{firstNonUnique};
        error(message('MATLAB:table:DuplicateVarNames', firstNonUniqueName));
    else
        newVarNames = reshape(allVarNames, 1, []);
        allAdaptors = cellfun(@(x) x.VariableAdaptors, inCell, 'UniformOutput', false);
        newAdaptors = [allAdaptors{:}];
        out = matlab.bigdata.internal.adaptors.TableAdaptor(newVarNames, newAdaptors);
    end
elseif any(strcmp(adaptorClasses, 'matlab.bigdata.internal.adaptors.CategoricalAdaptor'))
    % categorical can combine with: string, char, cell(str) - result is always categorical.
    uc = unique(underlyingClasses);
    % Remove unknown classes (which might error later)
    uc(isempty(uc)) = [];
    % Remove known-good classes, leaving only forbidden classes
    forbiddenClasses = setdiff(uc, { 'categorical', 'string', 'char', 'cell' });
    if isempty(forbiddenClasses)
        out = matlab.bigdata.internal.adaptors.CategoricalAdaptor();
    else
        error(message('MATLAB:bigdata:array:InvalidConcatenation', strjoin(uc, ' ')));
    end
else
    % Throw a vague error about not being able to concatenate
    error(message('MATLAB:bigdata:array:InvalidConcatenationUnknownTypes'));
end

% Attempt to propagate known size information by concatenating the sizes, but
% only if all small dimensions are known, and all classes are known and match
% (see g1393370 for what can happen when classes don't match - sizes can
% change!)
allNdims = cellfun(@(a) a.NDims, inCell);

if isscalar(inCell)
    out = copySizeInformation(out, inCell{1});
elseif ~any(isnan(allNdims)) && isKnownUniqueUnderlyingClass
    effectiveNdims = max(dim, max(allNdims));
    
    % Function to get the size from the adaptor in a vector of length
    % effectiveNdims.
    szAsCellFcn = @(a) { [a.Size, ones(1, max(0, effectiveNdims - a.NDims))] };

    % Get a matrix of all sizes
    allSizes = cell2mat(cellfun(szAsCellFcn, reshape(inCell, [], 1)));
    
    % Work out the dimensions for which we know the sizes
    knownSizeDims = all(~isnan(allSizes), 1);
    
    % We need matches in dimensions that are known and not the concatenation
    % dimension.
    checkDims      = knownSizeDims;
    checkDims(dim) = false;
    
    % Do the sizes match?
    sizesToCheck = allSizes(:, checkDims);
    doMatch = size(unique(sizesToCheck, 'rows'), 1) == 1;
    
    if doMatch
        newSize = allSizes(1, :);
        newSize(dim) = sum(allSizes(:, dim));
        out = setKnownSize(out, newSize);
    else
        error(message('MATLAB:bigdata:array:CatDimensionMismatch'));
    end
end