1 function [uniqueMat,varargout]=
uniquerows(inpMat,isInteger,forceMode)
3 persistent maxVal sqMaxVal logMaxVal;
8 varargout=cell(1,nOuts-1);
16 [nRows,nCols]=size(inpMat);
19 uniqueMat=inpMat(1,:);
24 [varargout{:}]=deal(ones(min(nRows,1),1));
30 isNum=isnumeric(inpMat);
32 isComplex=~isreal(inpMat);
34 % transform complex numbers to real ones separating them on real
37 indMat=feval(
class(inpMat),zeros(nRows,nCols));
38 indMat(:,1:2:nCols)=real(inpMat);
39 indMat(:,2:2:nCols)=imag(inpMat);
45 %
for simple situation use
unique 49 isInteger=~any(isMat);
53 [uniqueMat,varargout{:}]=
unique(inpMat,
'legacy');
56 curInd=find(isMat,1,
'last');
59 [uniqueMat,varargout{:}]=
unique(inpMat(isMat),
'legacy');
61 uniqueMat=[uniqueMat;NaN];
63 indRight2LeftVec=find(isMat);
64 varargout{1}=[indRight2LeftVec(varargout{1});curInd];
66 indLeft2RightVec=
repmat(numel(uniqueMat),nRows,1);
67 indLeft2RightVec(isMat)=varargout{2};
68 varargout{2}=indLeft2RightVec;
74 isForceMode=nargin>=3;
75 if isempty(maxVal)||isempty(sqMaxVal)||isempty(logMaxVal)
76 maxVal=1/eps(
'double');
77 sqMaxVal=sqrt(maxVal);
78 logMaxVal=log2(maxVal);
81 isIntType=isinteger(inpMat);
82 isLogicalType=islogical(inpMat);
83 isCharType=ischar(inpMat);
84 isInteger=isInteger||isIntType||isLogicalType||isCharType;
90 throwerror(
'wrongInput',
'type of inpMat is incorrect');
92 % reshape matrix into column vector
94 isMat=isfinite(indMat);
95 isAllFinite=all(isMat);
97 minInpVal=min(indMat);
98 maxInpVal=max(indMat);
100 % replace non-finite numbers by finite ones
101 uniqueMat=indMat(isMat);
102 % determine range of finite values
103 if isempty(uniqueMat)
107 minInpVal=min(uniqueMat);
108 maxInpVal=max(uniqueMat);
113 isCurMat(isMat)=indMat(isMat)==-Inf;
121 indMat(isCurMat)=nextVal;
124 isCurMat(isMat)=indMat(isMat)==Inf;
132 indMat(isCurMat)=nextVal;
135 isCurMat(isMat)=isnan(indMat(isMat));
140 [
'Range of values in inpMat is too large to ',...
141 'process it correctly']);
148 indMat(isCurMat)=nextVal;
151 rangeVal=maxInpVal-minInpVal+1;
152 if rangeVal<=sqMaxVal
153 isInteger=all(fix(indMat)==indMat);
154 isnOptimized=~isInteger;
157 if isInteger&&isnOptimized
158 % calculate range of values
164 maxInpVal=double(intmax(
'uint16'));
170 minInpVal=double(min(indMat));
171 maxInpVal=double(max(indMat));
173 % determine whether optimized version may be performed or not
174 rangeVal=maxInpVal-minInpVal+1;
175 isnOptimized=rangeVal>sqMaxVal;
178 isnOptimized=isnOptimized||~strcmpi(forceMode,
'optimized');
180 % determine what version (standard or optimized) is to be used
181 if rangeVal<=pow2(logMaxVal/nCols)
182 isOptimized=nRows>=500;
186 isnOptimized=~isOptimized;
188 % reshape indMat from column vector into matrix
if necessary
189 if isReshape&&~(isnOptimized&&isAllFinite)
190 indMat=reshape(indMat,nRows,nCols);
193 % perform built-in version of
unique 195 [uniqueMat,varargout{:}]=
unique(inpMat,
'rows',
'legacy');
197 [~,indRight2LeftVec,varargout{2:end}]=
unique(indMat,
'rows',...
199 uniqueMat=inpMat(indRight2LeftVec,:);
201 varargout{1}=indRight2LeftVec;
205 uniqueMat=complex(uniqueMat(:,1:2:nCols),uniqueMat(:,2:2:nCols));
209 % calculate codes
for rows
211 if ~isa(indMat,
'double')
212 indMat=
double(indMat);
214 indMat=indMat+(1-minInpVal);
215 indMat=indMat(:,nCols:-1:1); % flip columns to obtain desired sorting
216 allSizeVec=max(indMat,[],1);
220 % break all columns on segments
222 curInd=max(find(cumprod(allSizeVec(iCol+1:end))<=...
227 lenVec=horzcat(lenVec,curInd); %
#ok<AGROW> 231 auxCell=cell(1,nCols);
233 auxCell{iCol}=indMat(:,iCol);
238 %
get column vector with codes
239 indMat=sub2ind(allSizeVec,auxCell{:});
241 indMat=indMat(:,1:nCols);
242 sizeVec=nan(1,nCols);
244 lenVec(end)=lenVec(end)+nCurCols-sum(lenVec);
245 %
if necessary, process last segment with single column
247 indMat(:,nCols)=auxCell{nCurCols};
248 sizeVec(nCols)=allSizeVec(nCurCols);
253 %
get codes
for all segments
254 leftIndVec=[1 cumsum(lenVec(1:nCurCols-1))+1];
256 curInd=leftIndVec(iCol)+(0:lenVec(iCol)-1);
257 [uniqueLinInd,~,indMat(:,iCol)]=
unique(...
258 sub2ind(allSizeVec(curInd),auxCell{curInd}));
259 sizeVec(iCol)=length(uniqueLinInd);
264 % perform built-in
unique for codes
268 varargout{2}=ones(nRows,1);
271 [~,indRight2LeftVec,varargout{2:end}]=
unique(indMat);
273 uniqueMat=inpMat(indRight2LeftVec,:);
275 uniqueMat=complex(uniqueMat(:,1:2:nAllCols),uniqueMat(:,2:2:nAllCols));
278 varargout{1}=indRight2LeftVec;
function num2cell(in inpArray, in varargin)
NUM2CELL is an extension of Matlab built-in function "num2cell" designed to work correctly with empty...
function throwerror(in msgTag, in varargin)
THROWERROR works similarly to built-in ERROR function in case when there is no output arguments but s...
function uniquerows(in inpMat, in isInteger, in forceMode)
UNIQUEROWS finds unique rows in input matrix, i.e. the more effective version of UNIQUE(. . .,'rows')
function repmat(in inpArray, in varargin)
function unique(in inpVec)
UNIQUE for arrays of any type.