gusucode.com > datatypes 工具箱matlab源码程序 > datatypes/@categorical/subsasgn.m
function a = subsasgn(a,s,b) %SUBSASGN Subscripted assignment for a categorical array. % A = SUBSASGN(A,S,B) is called for the syntax A(I)=B. S is a structure % array with the fields: % type -- Character vector containing '()' specifying the subscript type. % Only parenthesis subscripting is allowed. % subs -- Cell array containing the actual subscripts. % % See also CATEGORICAL/CATEGORICAL, SUBSREF. % Copyright 2006-2016 The MathWorks, Inc. % Make sure nothing follows the () subscript if ~isscalar(s) error(message('MATLAB:categorical:InvalidSubscripting')); end creating = isnumeric(a) && isequal(a,[]); if creating % subscripted assignment to an array that doesn't exist a = b; % preserve the subclass a.codes = zeros(0,categorical.defaultCodesClass); end anames = a.categoryNames; numCatsOld = length(anames); switch s.type case '()' % Check numeric before builtin to short-circuit for performance and to % distinguish between '' and []. if isnumeric(b) && builtin('_isEmptySqrBrktLiteral',b) % Deleting elements, but the categories stay untouched. No need % to possibly downcast a.codes with castCodes. a.codes(s.subs{:}) = []; else if isa(b,'categorical') bcodes = b.codes; bnames = b.categoryNames; % If b is categorical, its ordinalness has to match a, and if they are % ordinal, their categories have to match. if a.isOrdinal ~= b.isOrdinal error(message('MATLAB:categorical:OrdinalMismatchAssign')); elseif isequal(anames,bnames) % Identical category names => same codes class => no cast needed for acodes else if a.isOrdinal error(message('MATLAB:categorical:OrdinalCategoriesMismatch')); end % Convert b's codes to a's codes. a's new set of categories grows only by % the categories that are actually being assigned, and a never needs to % care about the others in b that are not assigned. if isscalar(b) % When b is an <undefined> scalar, bcodes is already correct in % a's codes (undefCode is the same in all categoricals) and no % conversion is needed; otherwise, we can behave as if it only % has the one category, and conversion to a's codes is faster. if bcodes ~= 0 % categorical.undefCode [bcodes,anames] = convertCodesLocal(1,bnames{bcodes},anames,a.isProtected); end else [bcodes,anames] = convertCodesLocal(bcodes,bnames,anames,a.isProtected); end end elseif (ischar(b) && (isrow(b) || isequal(b,''))) || ... matlab.internal.datatypes.isCharStrings(b) || (isstring(b) && isscalar(b)) % inlined isCharString for performance [bcodes,bnames] = strings2codes(b); [bcodes,anames] = convertCodesLocal(bcodes,bnames,anames,a.isProtected); else error(message('MATLAB:categorical:InvalidRHS', class(a))); end % Upcast a's codes if necessary to account for any new categories if length(anames) > numCatsOld a.codes = categorical.castCodes(a.codes,length(anames)); end a.codes(s.subs{:}) = bcodes; a.categoryNames = anames; end case '{}' error(message('MATLAB:categorical:CellAssignmentNotAllowed')) case '.' error(message('MATLAB:categorical:FieldAssignmentNotAllowed')) end function [bcodes,anames] = convertCodesLocal(bcodes,bnames,anames,aprotect) % This is a version of convertCodes modified for the specifics of subsasgn. % Assigning from b into a, so: % * Need to return updated category names for a, not b, and a's list is grown % only by the (new) categories from b that are actually being assigned, % ignoring those that are not being assigned % * Don't care if b is protected % * If a is protected, only care if the values actually being assigned are not % categories in a. Unused categories in b not in a don't matter. try if ischar(bnames) ia = find(strcmp(bnames,anames)); if isempty(ia) if aprotect throwAsCaller(msg2exception('MATLAB:categorical:ProtectedForCombination')); end anames = [anames; bnames]; bcodes = length(anames); else bcodes = ia; end numCats = length(anames); if numCats > categorical.maxNumCategories throwAsCaller(msg2exception('MATLAB:categorical:MaxNumCategoriesExceeded',categorical.maxNumCategories)); end % Leave bcodes as a scalar double, main subsasgn function assigns it into % an integer array, so no cast needed here. else % iscellstr(bnames) % Get a's codes for b's data. Any elements of b that do not match a category of % a are assigned codes beyond a's range. [tf,ia] = ismember(bnames,anames); b2a = zeros(1,length(bnames)+1,categorical.defaultCodesClass); b2a = categorical.castCodes(b2a, length(anames)); % enough range to store ia, may upcast later b2a(2:end) = ia; % b has categories not present in a if ~all(tf) % Find b's categories that are actually being newly assigned into a. % Don't care about other categories in b but not in a. newlyAssigned(unique(bcodes(bcodes>0))) = true; newlyAssigned(tf) = false; % If a is protected we can't assign new categories. if any(newlyAssigned) if aprotect throwAsCaller(msg2exception('MATLAB:categorical:ProtectedForCombination')); end ib = find(newlyAssigned); numCats = length(anames) + length(ib); if numCats > categorical.maxNumCategories throwAsCaller(msg2exception('MATLAB:categorical:MaxNumCategoriesExceeded',categorical.maxNumCategories)); end % Append new categories corresponding to b's extras, possibly upcasting b2a b2a = categorical.castCodes(b2a, numCats); b2a(ib+1) = length(anames) + (1:length(ib)); anames = [anames; bnames(ib)]; end end bcodes = reshape(b2a(bcodes+1),size(bcodes)); end catch me if aprotect && strcmp(me.identifier,'MATLAB:categorical:ProtectedForCombination') names = setdiff(bnames,anames); throwAsCaller(msg2exception('MATLAB:categorical:ProtectedForAssign',names{1})); else throwAsCaller(me); end end