gusucode.com > symbolic工具箱matlab源码程序 > symbolic/private/symUnique.m

    function varargout = symUnique(varargin) 
%UNIQUE Set unique.
%   C = UNIQUE(A) for the array A returns the same values as in A but with 
%   no repetitions. C will be sorted.    
%  
%   C = UNIQUE(A,'rows') for the matrix A returns the unique rows of A.
%   The rows of the matrix C will be in sorted order.
%  
%   [C,IA,IC] = UNIQUE(A) also returns index vectors IA and IC such that
%   C = A(IA) and A = C(IC).  
%  
%   [C,IA,IC] = UNIQUE(A,'rows') also returns index vectors IA and IC such
%   that C = A(IA,:) and A = C(IC,:). 
%  
%   [C,IA,IC] = UNIQUE(A,OCCURRENCE) and
%   [C,IA,IC] = UNIQUE(A,'rows',OCCURRENCE) specify which index is returned
%   in IA in the case of repeated values (or rows) in A. The default value
%   is OCCURENCE = 'first', which returns the index of the first occurrence 
%   of each repeated value (or row) in A, while OCCURRENCE = 'last' returns
%   the index of the last occurrence of each repeated value (or row) in A.
%  
%   [C,IA,IC] = UNIQUE(A,'stable') returns the values of C in the same order
%   that they appear in A, while [C,IA,IC] = UNIQUE(A,'sorted') returns the
%   values of C in sorted order. If A is a row vector, then C will be a row
%   vector as well, otherwise C will be a column vector. IA and IC are
%   column vectors. If there are repeated values in A, then IA returns the
%   index of the first occurrence of each repeated value.
% 
%   [C,IA,IC] = UNIQUE(A,'rows','stable') returns the rows of C in the same
%   order that they appear in A, while [C,IA,IC] = UNIQUE(A,'rows','sorted')
%   returns the rows of C in sorted order.
% 
%   The behavior of UNIQUE has changed.  This includes:
%     -	occurrence of indices in IA and IC switched from last to first
%     -	IA and IC will always be column index vectors
% 
%   If this change in behavior has adversely affected your code, you may 
%   preserve the previous behavior with:
% 
%        [C,IA,IC] = UNIQUE(A,'legacy')
%        [C,IA,IC] = UNIQUE(A,'rows','legacy') 
%        [C,IA,IC] = UNIQUE(A,OCCURRENCE,'legacy')
%        [C,IA,IC] = UNIQUE(A,'rows',OCCURRENCE,'legacy')
%
%   Examples:
%
%       a = [9 9 9 9 9 9 8 8 8 8 7 7 7 6 6 6 5 5 4 2 1]
%
%       [c1,ia1,ic1] = unique(a)
%       % returns
%       c1 = [1 2 4 5 6 7 8 9]
%       ia1 = [21 20 19 18 16 13 10 6]
%       ic1 = [8 8 8 8 8 8 7 7 7 7 6 6 6 5 5 5 4 4 3 2 1]
%
%       [c2,ia2,ic2] = unique(a,'stable')
%       % returns
%       c2 = [9 8 7 6 5 4 2 1]
%       ia2 = [1 7 11 14 17 19 20 21]'
%       ic2 = [1 1 1 1 1 1 2 2 2 2 3 3 3 4 4 4 5 5 6 7 8]'
%
%       c = unique([1 NaN NaN 2])
%       % NaNs compare as not equal, so this returns
%       c = [1 2 NaN NaN]
%
%   Class support for input A:
%      - logical, char, all numeric classes
%      - cell arrays of strings
%      -- 'rows' option is not supported for cell arrays
%      - objects with methods SORT (SORTROWS for the 'rows' option) and NE
%      -- including heterogeneous arrays
%
%   See also UNION, INTERSECT, SETDIFF, SETXOR, ISMEMBER, SORT, SORTROWS.

%   Copyright 1984-2012 The MathWorks, Inc.

% Determine the number of outputs requested.

if nargout == 0
    nlhs = 1;
else
    nlhs = nargout;
end

narginchk(1,4);
nrhs = nargin;
if nrhs == 1
    [varargout{1:nlhs}] = uniqueR2012a(varargin{:});
else
    % acceptable combinations, with optional inputs denoted in []
    % unique(A, ['rows'], ['first'/'last'], ['legacy'/'R2012a']),
    % where the position of 'rows' and 'first'/'last' may be reversed
    % unique(A, ['rows'], ['sorted'/'stable']),
    % where the position of 'rows' and 'sorted'/'stable' may be reversed
    nflagvals = 7;
    flagvals = {'rows' 'first' 'last' 'sorted' 'stable' 'legacy' 'R2012a'};
    % When a flag is found, note the index into varargin where it was found
    flaginds = zeros(1,nflagvals);
    for i = 2:nrhs
        flag = varargin{i};
        foundflag = strcmpi(flag,flagvals);
        if ~any(foundflag)
            if ischar(flag)
                error(message('MATLAB:UNIQUE:UnknownFlag',flag));
            else
                error(message('MATLAB:UNIQUE:UnknownInput'));
            end
        end
        % Only 1 occurrence of each allowed flag value
        if flaginds(foundflag)
            error(message('MATLAB:UNIQUE:RepeatedFlag',flag));
        end
        flaginds(foundflag) = i;
    end
    
    % Only 1 of each of the paired flags
    if flaginds(2) && flaginds(3)
        error(message('MATLAB:UNIQUE:OccurrenceConflict'))
    end
    if flaginds(4) && flaginds(5)
        error(message('MATLAB:UNIQUE:SetOrderConflict'))
    end
    if flaginds(6) && flaginds(7)
        error(message('MATLAB:UNIQUE:BehaviorConflict'))
    end
    % 'legacy' and 'R2012a' flags must be trailing
    if flaginds(6) && flaginds(6)~=nrhs
        error(message('MATLAB:UNIQUE:LegacyTrailing'))
    end
    if flaginds(7) && flaginds(7)~=nrhs
        error(message('MATLAB:UNIQUE:R2012aTrailing'))
    end
    
    if flaginds(4) || flaginds(5) % 'stable'/'sorted' specified
        if flaginds(2) || flaginds(3) % does not combine with 'first'/'last'
            error(message('MATLAB:UNIQUE:SetOrderOccurrence'))
        end
        if flaginds(6) || flaginds(7) % does not combine with 'legacy'/'R2012a'
            error(message('MATLAB:UNIQUE:SetOrderBehavior'))
        end
        [varargout{1:nlhs}] = uniqueR2012a(varargin{1},logical(flaginds(1:5)));
    elseif flaginds(7) % trailing 'R2012a' specified
        [varargout{1:nlhs}] = uniqueR2012a(varargin{1},logical(flaginds(1:5)));
    elseif flaginds(6) % trailing 'legacy' specified
        [varargout{1:nlhs}] = uniquelegacy(varargin{1},logical(flaginds(1:3)));
    else % 'R2012a' (default behavior, to be changed to 'R2012a' in future)
        [varargout{1:nlhs}] = uniqueR2012a(varargin{1},logical(flaginds(1:5)));
    end
end
end

function [b,ndx,pos] = uniquelegacy(a,options)
% 'legacy' flag implementation 

%flagvals = {'rows' 'first' 'last'};
if nargin == 1
    byrow = false;
    order = 'last';
else
    byrow = (options(1) > 0);
    if options(2) > 0
        order = 'first';
    else % if options(3) > 0 || sum(options(2:3) == 0)
        order = 'last';
    end
end

rows = size(a,1);
cols = size(a,2);

rowvec = (rows == 1) && (cols > 1);

numelA = numel(a);
nOut = nargout;

    % Handle objects that cannot be converted to doubles     
    if ~byrow
        
        % Handle empty: no elements.
        
        if (numelA == 0)
            % Predefine b to be of the correct type.
            b = a([]);
            if max(size(a)) > 0
                b = reshape(b,0,1);
                ndx = zeros(0,1);
                pos = zeros(0,1);
            else
                ndx = [];
                pos = [];
            end
            return
            
        elseif (numelA == 1)
            % Scalar A: return the existing value of A.
            b = a; ndx = 1; pos = 1;
            return
            
            % General handling.
        else
            
            % Convert to columns
            a = a(:);
            
            % Sort if unsorted.  Only check this for long lists.
            
            if nOut <= 1
                b = sort(a);
            else
                [b,ndx] = sort(a);
            end
            
            % d indicates the location of non-matching entries.
            
            d = logical(b(1:numelA-1) ~= b(2:numelA));
            
            if order(1) == 'l' % 'last'
                d(numelA,1) = true; % Final element is always a member of unique list.
            else % order == 'first'
                d = [true; d];      % First element is always a member of unique list.
            end
            
            b = b(d);         % Create unique list by indexing into sorted list.
            
            if nOut == 3
                if order(1) == 'l' % 'last'
                    pos = cumsum([1;d]);        % Lists position, starting at 1.
                    pos(numelA+1) = [];         % Remove extra element introduced by d.
                else % order == 'first'
                    pos = cumsum(d);            % Lists position, starting at 1.
                end
                pos(ndx) = pos;             % Re-reference POS to indexing of SORT.
            end
            
            % Create indices if needed.
            if nOut > 1
                ndx = ndx(d);
            end
        end
        
        % If row vector, return as row vector.
        if rowvec
            b = b.';
            if nOut > 1
                ndx = ndx.';
                if nOut > 2
                    pos = pos.';
                end
            end
        end
        
    else    % 'rows' case
        
        % Handle empty: no rows.
        
        if (rows == 0)
            % Predefine b to be of the correct type.
            b = a([]);
            ndx = [];
            pos = [];
            b = reshape(b,0,cols);
            if cols > 0
                ndx = reshape(ndx,0,1);
            end
            return
            
            % Handle scalar: one row.
            
        elseif (rows == 1)
            b = a; ndx = 1; pos = 1;
            return
        end
        
        % General handling.
        
        if nOut > 1
            [b,ndx] = sortrows(a);
        else
            b = sortrows(a);
        end
        
        % d indicates the location of non-matching entries.
        
        d = logical(b(1:rows-1,:)~=b(2:rows,:));
        
        % d = 1 if differences between rows.  d = 0 if the rows are equal.
        
        d = any(d,2);
        if order(1) == 'l' % 'last'
            d(rows,1) = true; % Final row is always member of unique list.
        else % order == 'first'
            d = [true; d];    % First row is always a member of unique list.
        end
        
        b = b(d,:);         % Create unique list by indexing into sorted list.
        
        % Create position mapping vector using CUMSUM.
        
        if nOut == 3
            pos = cumsum([1;d]);        % Lists position, starting at 1.
            pos(rows+1) = [];           % Remove extra element introduced by d.
            pos(ndx) = pos;             % Re-reference POS to indexing of SORT.
        end
        
        % Create indices if needed.
        if nOut > 1
            ndx = ndx(d);
        end
    end
end


function [c,indA,indC] = uniqueR2012a(a,options)
% 'R2012a' flag implementaion

% flagvals = {'rows' 'first' 'last' 'sorted' 'stable'};
if nargin == 1
    byrow = false;
    order = 'sorted';
else
    byrow = (options(1) > 0);
    if options(5) > 0
        order = 'stable';
    elseif options(3) > 0
        order = 'last';
    else % if options(4) > 0 || options(2) || sum(options(2:5) == 0)  
        order = 'sorted';   %'first' and 'sorted' do the same thing
    end
end

% Determine if A is a row vector.
rowvec = isrow(a);

if ~byrow  % default case
    
    % Convert to column
    a = a(:);
    numelA = numel(a);
    
    % Sort A and get the indices if needed.
    if nargout > 1 || strcmp(order, 'stable')
        [sortA,indSortA] = sort(a);
    else
        sortA = sort(a);
    end
    
    % groupsSortA indicates the location of non-matching entries.
    if isnumeric(sortA) && (numelA > 1)
        dSortA = diff(sortA);
        if (isnan(dSortA(1)) || isnan(dSortA(numelA-1)))
            groupsSortA = sortA(1:numelA-1) ~= sortA(2:numelA);
        else
            groupsSortA = dSortA ~= 0;
        end
        
    else
        groupsSortA = logical(sortA(1:numelA-1) ~= sortA(2:numelA));
    end
    
    if (numelA ~= 0)
        if strcmp(order, 'last') 
            groupsSortA = [groupsSortA; true];          % Final element is always a member of unique list.
        else  % if (strcmp(order, 'sorted') || strcmp(order, 'stable')) 
            groupsSortA = [true; groupsSortA];          % First element is always a member of unique list.
        end
    else
        groupsSortA = zeros(0,1);
    end
    
    % Extract unique elements.
    if strcmp(order, 'stable') 
        invIndSortA = indSortA;
        invIndSortA(invIndSortA) = 1:numelA;  % Find inverse permutation.
        logIndA = groupsSortA(invIndSortA);   % Create new logical by indexing into groupsSortA.
        c = a(logIndA);                       % Create unique list by indexing into unsorted a.
    else
        c = sortA(groupsSortA);         % Create unique list by indexing into sorted list.
    end
    
    % Find indA.
    if nargout > 1
        if strcmp(order, 'stable') 
            indA = find(logIndA);           % Find the indices of the unsorted logical.
        else
            indA = indSortA(groupsSortA);   % Find the indices of the sorted logical.
        end
    end
    
    % Find indC.
    if nargout == 3
        groupsSortA = full(groupsSortA);
        if numelA == 0
            indC = zeros(0,1);
        else
            switch order
                case 'last'
                    indC = cumsum([1;groupsSortA(1:end-1)]);            % Lists position, starting at 1.
                    indC(indSortA) = indC;                              % Re-reference indC to indexing of sortA.
                case 'sorted' 
                    indC = cumsum(groupsSortA);                         % Lists position, starting at 1.
                    indC(indSortA) = indC;                              % Re-reference indC to indexing of sortA.
                otherwise % 'stable'
                    [~,indSortC] = sort(c);                             % Sort C to get index.
                    
                    lengthGroupsSortA = diff(find([groupsSortA; true]));  % Determine how many of each of the above indices there are in IC.
                    
                    diffIndSortC = diff(indSortC);                        % Get the correct amount of each index.
                    diffIndSortC = [indSortC(1); diffIndSortC];
                    
                    indLengthGroupsSortA = cumsum([1; lengthGroupsSortA]);
                    indLengthGroupsSortA(end) = [];
                    
                    indCOrderedBySortA(indLengthGroupsSortA,1) = diffIndSortC;        % Since indCOrderedBySortA is not already established as a column,
                    if sum(lengthGroupsSortA) ~= length(indCOrderedBySortA);        % This is false if all the elements in A originally were unique and
                        indCOrderedBySortA(sum(lengthGroupsSortA),1) = 0;             % true if the original A had duplicates.
                    end
                    
                    indCOrderedBySortA = cumsum(indCOrderedBySortA);
                    indC = indCOrderedBySortA(invIndSortA);                 % Reorder the list of indices to the unsorted order.
            end
        end
    end
    
    % If A is row vector, return C as row vector.
    if rowvec
        c = c.';
    end
    
else    % 'rows' case
    if ~ismatrix(a)
        error(message('MATLAB:UNIQUE:ANotAMatrix'));
    end
    
    numRows = size(a,1);
    numCols = size(a,2);
    
    % Sort A and get the indices if needed.
    if nargout > 1 || strcmp(order, 'stable') 
        [sortA,indSortA] = sortrows(a);
    else
        sortA = sortrows(a);
    end
    
    % groupsSortA indicates the location of non-matching entries.
    groupsSortA = logical(sortA(1:numRows-1,:) ~= sortA(2:numRows,:));
    groupsSortA = any(groupsSortA,2);
    if (numRows ~=0)
        if strcmp(order, 'last') 
            groupsSortA = [groupsSortA; true];          % Final row is always member of unique list.
        else  % if (strcmp(order, 'sorted') || strcmp(order, 'stable')) 
            groupsSortA = [true; groupsSortA];          % First row is always a member of unique list.
        end
    end
    
    % Extract Unique elements.
    if strcmp(order, 'stable')
        invIndSortA = indSortA;
        invIndSortA(invIndSortA) = 1:numRows;               % Find the inverse permutation of indSortA.
        logIndA = groupsSortA(invIndSortA);                 % Create new logical by indexing into groupsSortA.
        c = a(logIndA,:);                                   % Create unique list by indexing into unsorted a.
    else
        c = sortA(groupsSortA,:);         % Create unique list by indexing into sorted list.
    end
    
    % Find indA.
    if nargout > 1
        if strcmp(order, 'stable')
            indA = find(logIndA);           % Find the indices of the unsorted logical.
        else
            indA = indSortA(groupsSortA);   % Find the indices of the sorted logical.
        end
    end
    
    % Find indC.
    if nargout == 3
        groupsSortA = full(groupsSortA);
        switch order
            case 'last' 
                if (numRows == 0)
                    indC = cumsum(groupsSortA);                         % Empty A - use all of groupsSortA.
                    indC(indSortA) = indC;
                else
                    indC = cumsum([1;full(groupsSortA(1:end-1))]);      % Lists position, starting at 1.
                    indC(indSortA) = indC;                              % Re-reference indC to indexing of sortA.
                end
            case 'sorted' 
                indC = cumsum(groupsSortA);                             % Lists position, starting at 1.
                indC(indSortA) = indC;                                  % Re-reference indC to indexing of sortA.
            otherwise % 'stable'
                if numCols == 0
                    indC = ones(numRows,1);                             % For 'stable' ensure that empty A gives correct size and shape.
                elseif numRows == 0
                    indC = zeros(0,1);
                else
                    [~,indSortC] = sortrows(c);                         % Sort C to get index.
                    
                    lengthGroupsSortA = diff(find([groupsSortA; true]));    % Determine how many of each of the above indices there are in IC.
                    
                    diffIndSortC = diff(indSortC);
                    diffIndSortC = [indSortC(1); diffIndSortC];
                    
                    indLengthGroupsSortA = cumsum([1; lengthGroupsSortA]);  % Get the correct amount of each index.
                    indLengthGroupsSortA(end) = [];
                    
                    indCOrderedBySortA(indLengthGroupsSortA,1) = diffIndSortC;        % Since indCOrderedBySortA is not already established as a column,
                   
                    if sum(lengthGroupsSortA) ~= length(indCOrderedBySortA);
                        indCOrderedBySortA(sum(lengthGroupsSortA),1) = 0;
                    end
                    
                    indCOrderedBySortA = cumsum(indCOrderedBySortA);
                    indC = indCOrderedBySortA(invIndSortA);                 % Reorder the list of indices to the unsorted order.
                end
        end
    end
end
end