gusucode.com > datatypes 工具箱matlab源码程序 > datatypes/@tabular/subsasgnDot.m
function t = subsasgnDot(t,s,b,deleting) %SUBSASGNDOT Subscripted assignment to a table. % Copyright 2012-2016 The MathWorks, Inc. % '.' is assignment to or into a variable. Any sort of subscripting % may follow that, and row labels are inherited from the table. import matlab.internal.tableUtils.emptyLike import matlab.internal.datatypes.isCharString import matlab.internal.datatypes.istabular import matlab.internal.tableUtils.isScalarInt subsType = matlab.internal.table.tableDimension.subsType; % "import" for calls to subs2inds if ~isstruct(s), s = struct('type','.','subs',s); end % For built-in tyes, s(2).type=='()' guarantees that length(s)==2, but for a var that % is itself a table, parens need not be the end. deletion other than t.Var or t.Var(...) % is handled by the assignment code path. if nargin < 4 deleting = isnumeric(b) && builtin('_isEmptySqrBrktLiteral',b) ... && (isscalar(s) || ((length(s) == 2) && isequal(s(2).type,'()'))); end t_nrows = t.rowDim.length; t_nvars = t.varDim.length; % Translate variable (column) name into an index. Avoid overhead of % t.varDim.subs2inds as much as possible in this simple case. varName = s(1).subs; if isnumeric(varName) % Allow t.(i) where i is an integer varIndex = varName; if ~isScalarInt(varName,1) error(message('MATLAB:table:IllegalVarIndex')); end isNewVar = (varIndex > t_nvars); if isNewVar if deleting error(message('MATLAB:table:VarIndexOutOfRange')); elseif varIndex > t_nvars+1 error(message('MATLAB:table:DiscontiguousVars')); else [~,~,~,~,updatedVarDim] = t.varDim.subs2inds(varIndex,subsType.assignment); varName = updatedVarDim.labels{varIndex}; end end elseif ischar(varName) && (isrow(varName) || isequal(varName,'')) % isCharString(varName) varIndex = find(strcmp(varName,t.varDim.labels)); isNewVar = false; % assume for now, update below if isempty(varIndex) % Check against reserved names first as a failsafe against shadowing % .Properties by a dimension name. if ~deleting && matlab.internal.table.checkReservedNames(varName,'varnames') % one name, don't need to wrap with any() % Handle assignment to a property under the 'Properties' (virtual) % property, or to the entire 'Properties' property. if strcmp(varName,'Properties') try if isscalar(s) t = setProperties(t,b); else t = setProperty(t,s(2:end),b); end catch ME if ~isscalar(s) && strcmp(ME.identifier,'MATLAB:table:UnknownProperty') propName = s(2).subs; match = find(strcmpi(propName,t.propertyNames),1); if ~isempty(match) % a property name. but with wrong case match = t.propertyNames{match}; error(message('MATLAB:table:UnknownPropertyCase',propName,match)); else throw(ME); end else throw(ME); end end return else % t.VariableNames or t.RowNames error(message('MATLAB:table:InvalidPropertyAssignment',varName,varName)); end elseif strcmp(varName,t.metaDim.labels{1}) % If it's the row dimension name, assign to the row labels varIndex = 0; % For assignments onto the row labels, accept any vector. For assignments % into, leave the RHS alone. if isscalar(s) if isvector(b), b = b(:); end elseif deleting % && ~isscalar(s) error(message('MATLAB:table:NestedSubscriptingWithDotRowsDeletion',t.metaDim.labels{1})); end elseif strcmp(varName,t.metaDim.labels{2}) % If it's the vars dimension name, assign to t{:,:}. Deeper subscripting % is not supported, use explicit braces for that. if ~isscalar(s) error(message('MATLAB:table:NestedSubscriptingWithDotVariables',t.metaDim.labels{2})); end varIndex = -1; elseif deleting error(message('MATLAB:table:UnrecognizedVarNameDeleting',varName,varName)); else isNewVar = true; matlab.internal.tableUtils.makeValidName(varName,'varnamesError'); % error if invalid % If this is a new variable, it will go at the end. varIndex = t_nvars + 1; updatedVarDim = t.varDim.lengthenTo(varIndex,{varName}); end end else error(message('MATLAB:table:IllegalVarSubscript')); end % Handle empty assignment intended as deletion of an entire variable or of % columns/pages/etc. of a variable. Deletion of rows in a (single) % variable is caught here and not allowed. Other empty assignment % syntaxes may be assignment to cells or may be deletion of things deeper % in a non-atomic variable, neither is handled here. if deleting % Syntax: t.var = [] % % Delete an entire variable. if isscalar(s) if varIndex > 0 t.data(varIndex) = []; t.varDim = t.varDim.deleteFrom(varIndex); elseif varIndex == 0 t.rowDim = t.rowDim.removeLabels(); % this might error else % varindex == -1 varIndex = 1:t.varDim.length; t.data(varIndex) = []; t.varDim = t.varDim.deleteFrom(varIndex); end % Syntax: t.var(:,...) = [] % t.var(rowIndices,...) = [] is illegal % % Delete columns/pages/etc. of a variable, with ':' as the first index % in subscript. This may change the dimensionality of the variable, % but won't change the number of rows because we require ':' as the % first index. else % length(s) == 2 if ~iscolon(s(2).subs{1}) error(message('MATLAB:table:EmptyAssignmentToVariableRows')); elseif isscalar(s(2).subs) error(message('MATLAB:table:EmptyAssignmentToAllVariableElements')); end var_j = t.data{varIndex}; try %#ok<ALIGN> if istabular(var_j) var_j = subsasgnParens(var_j,s(2),[],false,true); % can't use table subscripting directly else var_j(s(2).subs{:}) = []; end catch ME, throw(ME); end t.data{varIndex} = var_j; end else % Syntax: t.var = b % % Replace an entire variable. It must have the right number of rows, unless % the LHS is 0x0. updatedRowDim = []; if isscalar(s) if size(b,1) ~= t_nrows && (t_nrows+t_nvars > 0) % If the assignment has the wrong number of rows, check for some % common mistakes to suggest what may have been intended if strcmpi(varName,'Properties') && isstruct(b) && isscalar(b) % Things like t.properties = scalarStruct str = getString(message('MATLAB:table:IntendedPropertiesAssignment')); error(message('MATLAB:table:RowDimensionMismatchSuggest',str)); else match = find(strcmpi(varName,t.propertyNames),1); if ~isempty(match) % Things like t.PropertyName = ... match = t.propertyNames{match}; str = getString(message('MATLAB:table:IntendedPropertyAssignment',match,match)); error(message('MATLAB:table:RowDimensionMismatchSuggest',str)); end end % Anything else, no suggestion. No point in checking for a case % insensitive match to an existing var, even with the correct case, % this would still be an illegal assignment error(message('MATLAB:table:RowDimensionMismatch')); end var_j = b; % Syntax: t.var(rowIndices,...) = b % t.var{rowIndices,...} = b % t.var{rowIndices,...} = [] (this is assignment, not deletion) % t.var.field = b % % Assign to elements in a variable. Assignment can also be used to % expand the variable's number of rows, or along another dimension. % % Cell indexing, e.g. t.var{rowIndices,...}, or a reference to a % field, e.g. t.var.field, may also be followed by deeper levels of % subscripting. Cannot create a new var implicitly by deeper indexing. else % ~isscalar(s) if isNewVar && (length(s) > 2) && ~isequal(s(2).type,'.') % If the assignment is not to an existing var, check for some common % mistakes to suggest what may have been intended match = find(strcmpi(varName,t.varDim.labels),1); if ~isempty(match) % An existing variable name, but with wrong case match = t.varDim.labels{match}; str = getString(message('MATLAB:table:IntendedVarAssignment',match)); error(message('MATLAB:table:InvalidExpansionDotDepthSuggest',str)); end % Anything else, no suggestion error(message('MATLAB:table:InvalidExpansionDotDepth')); end if isequal(s(2).type,'.') % dot indexing into variable % If the assignment is not to an existing var, check for some common % mistakes to suggest what may have been intended if isNewVar if strcmpi(varName,'Properties') && isCharString(s(2).subs) % Things like t.properties.name str = getString(message('MATLAB:table:IntendedPropertiesAssignment')); error(message('MATLAB:table:InvalidExpansionDotSuggest',str)); else match = find(strcmpi(varName,t.varDim.labels),1); if ~isempty(match) % An existing variable name, but with wrong case match = t.varDim.labels{match}; str = getString(message('MATLAB:table:IntendedVarAssignment',match)); error(message('MATLAB:table:InvalidExpansionDotSuggest',str)); else % Anything else, no suggestion error(message('MATLAB:table:InvalidExpansionDot')); end end end if varIndex > 0 var_j = t.data{varIndex}; elseif varIndex == 0 var_j = t.rowDim.labels; else % varIndex == -1 assert(false); end else % () or {} subscripting into variable % Initialize a new var, or extract an existing var. if isNewVar % Start the new var out as an empty of b's class with % the same number of rows as the table. var_j = emptyLike([t_nrows,0],'Like',b); else if varIndex > 0 var_j = t.data{varIndex}; elseif varIndex == 0 var_j = t.rowDim.labels; else % varIndex == -1 assert(false); end end % The variable inherits row labels from the table. Translate labels to % row numbers if necessary. rowIndices = s(2).subs{1}; if isnumeric(rowIndices) || islogical(rowIndices) || iscolon(rowIndices) % Can leave these alone to save overhead of calling subs2inds else % Row labels may be used as a "linear index" only if the variable % has a single column. if ~iscolumn(var_j) && isscalar(s(2).subs) error(message('MATLAB:table:InvalidLinearIndexing')); end end % subs2inds returns the indices as a col vector, which prevents reshaping. % This is fine because the var is constrained inside the table. [rowIndices,~,~,~,updatedRowDim] = t.rowDim.subs2inds(rowIndices,subsType.assignment); s(2).subs{1} = rowIndices; end % Now let the variable's subsasgn handle the subscripting in % things like t.name(...) or t.name{...} or t.name.attribute % Calling subsasgn directly allows changing the shape of var_j by % assignment, which the interpreter would not allow. if length(s) == 2 if isobject(var_j) % If b is superior to var_j, this will dispatch to b try %#ok<ALIGN> var_j = subsasgn(var_j,s(2),b); catch ME, throw(ME); end else % Call builtin, to get correct dispatching even if b is an object. try %#ok<ALIGN> var_j = builtin('subsasgn',var_j,s(2),b); catch ME, throw(ME); end end else % length(s) > 2 % Trick the third and higher levels of subscripting in things like % t.Var{i}(...) etc. into dispatching to the right place even when % t.Var{i}, or something further down the chain, is itself a table. try %#ok<ALIGN> var_j = matlab.internal.table.subsasgnRecurser(var_j,s(2:end),b); catch ME, rethrow(ME); end % point to the line in subsasgnRecurser end end % If this is a new variable, make it official. if isNewVar t.varDim = updatedVarDim; end % If an entire var was replaced or created, the new value was required to % have the same number of rows as the table. However, when assigning into a % new var, the assignment might create something shorter than the table, so % check for that and lengthen the new var to match the table. In most % cases, assigning into an existing var leaves it as the correct height, % although in at least one oddball case (assigning a field to a non-struct), % assigning into an existing var can make the result shorter then it was % originally, so check for those too. varLen = size(var_j,1); if varLen < t_nrows % t's original number of rows warning(message('MATLAB:table:RowsAddedNewVars')); var_j = matlab.internal.table.lengthenVar(var_j,t_nrows); end if varIndex > 0 t.data{varIndex} = var_j; elseif varIndex == 0 t.rowDim = t.rowDim.setLabels(var_j); else % varIndex == -1 t = subsasgnBraces(t,{':' ':'},var_j); end % If the var being assigned to is now taller than the table, add rows to % the rest of the table, including row labels. This might be because the % assignment lengthened an existing var, or because an "into" assignment % created a new var taller than the table. Warn only if we have to lengthen % existing vars that have not been assigned to -- if there's currently only % one var in the table (which might be existing or new), don't warn about % any default values "filled in in the middle". if varLen > t_nrows % t's original number of rows if t.varDim.length > 1 % some existing vars were not assigned to warning(message('MATLAB:table:RowsAddedExistingVars')); end if isempty(updatedRowDim) t.rowDim = t.rowDim.lengthenTo(varLen); else t.rowDim = updatedRowDim; end t = lengthenTableVars(t,varLen); % updates nrows end end