Mercurial > octave-dspies
diff scripts/set/unique.m @ 19003:d00f6b09258f @
Overhaul functions in scripts/set directory.
* set.txi: Rewrite documentation for set functions.
* intersect.m: Rewrite docstring. Use by_rows variable for code clarity.
Return output orientation which is compatible with Matlab. Add %!tests for
output orientation and N-dimensional inputs.
* setdiff.m: Rewrite docstring. Use by_rows variable for code clarity.
Rename output i to ia to clarify it is an index into the set a.
Return output orientation which is compatible with Matlab. Add %!tests for
N-dimensional inputs.
* setxor.m: Rewrite docstring. Use by_rows variable for code clarity.
Return output orientation which is compatible with Matlab. Add %!tests for
output orientation and N-dimensional inputs.
* union.m: Rewrite docstring. Use by_rows variable for code clarity.
Return output orientation which is compatible with Matlab. Add %!tests for
output orientation and N-dimensional inputs. Add %!tests for validsetargs
which are common to all set functions.
* unique.m: Rewrite docstring. Verify that input is numeric or cell array
of strings. Avoid computing idx for optional i,j outputs unless required.
Add %!error tests for input validation.
* ismember.m: Rewrite docstring. Use input variable 'a' instead of 'A' for
conformance with rest of set functions. Rename output index variable to
s_idx for clarity that it is an index into the set s.
* powerset.m: Rewrite doctring. Add input validation on nargin. Add %!error
input validation tests.
* module.mk: Include validsetargs.m in build system.
* validsetargs.m: Function renamed from validargs which was too general.
* validargs.m: Function renamed to validsetargs.
author | Rik <rik@octave.org> |
---|---|
date | Mon, 11 Aug 2014 09:39:45 -0700 |
parents | 7bbe3658c5ef |
children |
line wrap: on
line diff
--- a/scripts/set/unique.m Sun Aug 10 08:18:18 2014 -0700 +++ b/scripts/set/unique.m Mon Aug 11 09:39:45 2014 -0700 @@ -20,20 +20,20 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} unique (@var{x}) ## @deftypefnx {Function File} {} unique (@var{x}, "rows") -## @deftypefnx {Function File} {} unique (@dots{}, "first") -## @deftypefnx {Function File} {} unique (@dots{}, "last") ## @deftypefnx {Function File} {[@var{y}, @var{i}, @var{j}] =} unique (@dots{}) -## Return the unique elements of @var{x}, sorted in ascending order. -## If the input @var{x} is a vector then the output is also a vector with the -## same orientation (row or column) as the input. For a matrix input the -## output is always a column vector. @var{x} may also be a cell array of -## strings. +## @deftypefnx {Function File} {[@var{y}, @var{i}, @var{j}] =} unique (@dots{}, "first") +## @deftypefnx {Function File} {[@var{y}, @var{i}, @var{j}] =} unique (@dots{}, "last") +## Return the unique elements of @var{x} sorted in ascending order. ## -## If the optional argument @qcode{"rows"} is supplied, return the unique -## rows of @var{x}, sorted in ascending order. +## If the input @var{x} is a column vector then return a column vector; +## Otherwise, return a row vector. @var{x} may also be a cell array of strings. +## +## If the optional argument @qcode{"rows"} is given then return the unique +## rows of @var{x} sorted in ascending order. The input must be a 2-D matrix +## to use this option. ## ## If requested, return index vectors @var{i} and @var{j} such that -## @code{x(i)==y} and @code{y(j)==x}. +## @code{@var{y} = @var{x}(@var{i})} and @code{@var{x} = @var{y}(@var{j})}. ## ## Additionally, if @var{i} is a requested output then one of @qcode{"first"} or ## @qcode{"last"} may be given as an input. If @qcode{"last"} is specified, @@ -46,34 +46,32 @@ if (nargin < 1) print_usage (); + elseif (! (ismatrix (x) || iscellstr (x))) + error ("unique: X must be a matrix or cell array of strings"); endif if (nargin > 1) ## parse options - if (iscellstr (varargin)) - optfirst = strcmp ("first", varargin); - optlast = strcmp ("last", varargin); - optrows = strcmp ("rows", varargin); - if (! all (optfirst | optlast | optrows)) - error ("unique: invalid option"); - endif - optfirst = any (optfirst); - optlast = any (optlast); - optrows = any (optrows); - if (optfirst && optlast) - error ('unique: cannot specify both "last" and "first"'); - endif - else + if (! iscellstr (varargin)) error ("unique: options must be strings"); endif - if (optrows && iscell (x)) + optrows = any (strcmp ("rows", varargin)); + optfirst = any (strcmp ("first", varargin)); + optlast = any (strcmp ("last", varargin)); + if (optfirst && optlast) + error ('unique: cannot specify both "first" and "last"'); + elseif (optfirst + optlast + optrows != nargin-1) + error ("unique: invalid option"); + endif + + if (optrows && iscellstr (x)) warning ('unique: "rows" is ignored for cell arrays'); optrows = false; endif else + optrows = false; optfirst = false; - optrows = false; endif ## FIXME: The operations @@ -87,7 +85,7 @@ if (issparse (x) && ! optrows && nargout <= 1) if (nnz (x) < numel (x)) - y = unique ([0; (full (nonzeros (x)))], varargin{:}); + y = unique ([0; nonzeros(x)], varargin{:}); else ## Corner case where sparse matrix is actually full y = unique (full (x), varargin{:}); @@ -107,7 +105,7 @@ ## Special cases 0 and 1 if (n == 0) if (! optrows && isempty (x) && any (size (x))) - if (iscell (y)) + if (iscellstr (y)) y = cell (0, 1); else y = zeros (0, 1, class (y)); @@ -127,8 +125,7 @@ y = sortrows (y); endif match = all (y(1:n-1,:) == y(2:n,:), 2); - idx = find (match); - y(idx,:) = []; + y(match,:) = []; else if (! isvector (y)) y = y(:); @@ -138,13 +135,12 @@ else y = sort (y); endif - if (iscell (y)) + if (iscellstr (y)) match = strcmp (y(1:n-1), y(2:n)); else match = (y(1:n-1) == y(2:n)); endif - idx = find (match); - y(idx) = []; + y(match) = []; endif if (isargout (3)) @@ -157,25 +153,25 @@ endif if (isargout (2)) + idx = find (match); if (optfirst) - i(idx+1) = []; - else - i(idx) = []; + idx += 1; # in-place is faster than other forms of increment endif + i(idx) = []; endif endfunction -%!assert (unique ([1 1 2; 1 2 1; 1 1 2]),[1;2]) -%!assert (unique ([1 1 2; 1 0 1; 1 1 2],"rows"),[1 0 1; 1 1 2]) -%!assert (unique ([]),[]) -%!assert (unique ([1]),[1]) -%!assert (unique ([1 2]),[1 2]) -%!assert (unique ([1;2]),[1;2]) -%!assert (unique ([1,NaN,Inf,NaN,Inf]),[1,Inf,NaN,NaN]) -%!assert (unique ({"Foo","Bar","Foo"}),{"Bar","Foo"}) -%!assert (unique ({"Foo","Bar","FooBar"}'),{"Bar","Foo","FooBar"}') +%!assert (unique ([1 1 2; 1 2 1; 1 1 2]), [1;2]) +%!assert (unique ([1 1 2; 1 0 1; 1 1 2],"rows"), [1 0 1; 1 1 2]) +%!assert (unique ([]), []) +%!assert (unique ([1]), [1]) +%!assert (unique ([1 2]), [1 2]) +%!assert (unique ([1;2]), [1;2]) +%!assert (unique ([1,NaN,Inf,NaN,Inf]), [1,Inf,NaN,NaN]) +%!assert (unique ({"Foo","Bar","Foo"}), {"Bar","Foo"}) +%!assert (unique ({"Foo","Bar","FooBar"}'), {"Bar","Foo","FooBar"}') %!assert (unique (zeros (1,0)), zeros (0,1)) %!assert (unique (zeros (1,0), "rows"), zeros (1,0)) %!assert (unique (cell (1,0)), cell (0,1)) @@ -192,6 +188,7 @@ %!assert (unique (uint8 ([1,2,2,3,2,4]), "rows"), uint8 ([1,2,2,3,2,4])) %!assert (unique (uint8 ([1,2,2,3,2,4])), uint8 ([1,2,3,4])) %!assert (unique (uint8 ([1,2,2,3,2,4]'), "rows"), uint8 ([1,2,3,4]')) + %!test %! [a,i,j] = unique ([1,1,2,3,3,3,4]); %! assert (a, [1,2,3,4]); @@ -217,8 +214,15 @@ %! assert (A(i,:), a); %! assert (a(j,:), A); -%!error unique({"a", "b", "c"}, "UnknownOption") -%!error unique({"a", "b", "c"}, "UnknownOption1", "UnknownOption2") -%!error unique({"a", "b", "c"}, "rows", "UnknownOption2") -%!error unique({"a", "b", "c"}, "UnknownOption1", "last") +%% Test input validation +%!error unique () +%!error <X must be a matrix or cell array of strings> unique ({1}) +%!error <options must be strings> unique (1, 2) +%!error <cannot specify both "first" and "last"> unique (1, "first", "last") +%!error <invalid option> unique (1, "middle") +%!error <invalid option> unique ({"a", "b", "c"}, "UnknownOption") +%!error <invalid option> unique ({"a", "b", "c"}, "UnknownOption1", "UnknownOption2") +%!error <invalid option> unique ({"a", "b", "c"}, "rows", "UnknownOption2") +%!error <invalid option> unique ({"a", "b", "c"}, "UnknownOption1", "last") +%!warning <"rows" is ignored for cell arrays> unique ({"1"}, "rows");