diff scripts/set/setdiff.m @ 27237:67e5e997a3bf

setdiff.m: Accept a "legacy" flag for Matlab compatibility. * NEWS: Announce change to setdiff return values when given "rows" argument. Announce "legacy" flag. * setdiff.m Add new calling form and explanation of "legacy" option to docstring. Allow up to 4 inputs in input validation. Check for "legacy" in input options and set variable optlegacy. Set variable isrowvec based on optlegacy and orientation of inputs. Add BIST tests for "rows" and "legacy" inputs.
author Rik <rik@octave.org>
date Thu, 11 Jul 2019 15:29:38 -0700
parents 00f796120a6d
children 6525b3fe3cf9
line wrap: on
line diff
--- a/scripts/set/setdiff.m	Thu Jul 11 15:05:30 2019 -0700
+++ b/scripts/set/setdiff.m	Thu Jul 11 15:29:38 2019 -0700
@@ -20,6 +20,7 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{c} =} setdiff (@var{a}, @var{b})
 ## @deftypefnx {} {@var{c} =} setdiff (@var{a}, @var{b}, "rows")
+## @deftypefnx {} {@var{c} =} setdiff (@dots{}, "legacy")
 ## @deftypefnx {} {[@var{c}, @var{ia}] =} setdiff (@dots{})
 ## Return the unique elements in @var{a} that are not in @var{b} sorted in
 ## ascending order.
@@ -33,6 +34,10 @@
 ##
 ## If requested, return the index vector @var{ia} such that
 ## @code{@var{c} = @var{a}(@var{ia})}.
+##
+## Programming Note: The input flag @qcode{"legacy"} changes the algorithm
+## to be compatible with @sc{matlab} releases prior to R2012b.
+##
 ## @seealso{unique, union, intersect, setxor, ismember}
 ## @end deftypefn
 
@@ -41,24 +46,30 @@
 
 function [c, ia] = setdiff (a, b, varargin)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2 || nargin > 4)
     print_usage ();
   endif
 
   [a, b] = validsetargs ("setdiff", a, b, varargin{:});
 
-  by_rows = nargin == 3;
-  isrowvec = isrow (a);
+  by_rows = any (strcmp ("rows", varargin));
+  optlegacy = any (strcmp ("legacy", varargin));
+
+  if (optlegacy)
+    isrowvec = ! iscolumn (a) || ! iscolumn (b);
+  else
+    isrowvec = isrow (a);
+  endif
 
   if (by_rows)
     if (nargout > 1)
-      [c, ia] = unique (a, "rows");
+      [c, ia] = unique (a, varargin{:});
     else
-      c = unique (a, "rows");
+      c = unique (a, varargin{:});
     endif
     if (! isempty (c) && ! isempty (b))
       ## Form A and B into combined set.
-      b = unique (b, "rows");
+      b = unique (b, varargin{:});
       [tmp, idx] = sortrows ([c; b]);
       ## Eliminate those elements of A that are the same as in B.
       dups = find (all (tmp(1:end-1,:) == tmp(2:end,:), 2));
@@ -69,9 +80,9 @@
     endif
   else
     if (nargout > 1)
-      [c, ia] = unique (a);
+      [c, ia] = unique (a, varargin{:});
     else
-      c = unique (a);
+      c = unique (a, varargin{:});
     endif
     if (! isempty (c) && ! isempty (b))
       ## Form a and b into combined set.
@@ -84,15 +95,18 @@
         dups = find (tmp(1:end-1) == tmp(2:end));
       endif
       c(idx(dups)) = [];
-      if (nargout > 1)
-        ia(idx(dups)) = [];
-      endif
       ## Reshape if necessary for Matlab compatibility.
       if (isrowvec)
         c = c(:).';
       else
         c = c(:);
       endif
+      if (nargout > 1)
+        ia(idx(dups)) = [];
+        if (optlegacy && isrowvec)
+          ia = ia(:).';
+        endif
+      endif
     endif
   endif
 
@@ -126,3 +140,36 @@
 %! a = rand (3,3,3);
 %! b = a(1);
 %! assert (setdiff (a, b), sort (a(2:end)'));
+
+## Test "rows" compatibility
+%!test
+%! a = [7 9 7; 0 0 0; 7 9 7; 5 5 5; 1 4 5];
+%! b = [0 0 0; 5 5 5];
+%! [c, ia] = setdiff (a, b, "rows");
+%! assert (c, [1, 4 ,5; 7, 9 7]);
+%! assert (ia, [5; 1]);
+
+## Test "legacy" option
+%!test
+%! a = [3, 6, 2, 1, 5, 1, 1];
+%! b = [2, 4, 6];
+%! [c, ia] = setdiff (a, b);
+%! assert (c, [1, 3, 5]);
+%! assert (ia, [4; 1; 5]);
+%! [c, ia] = setdiff (a, b, "legacy");
+%! assert (c, [1, 3, 5]);
+%! assert (ia, [7, 1, 5]);
+
+## "legacy" + "rows" compatibility
+%!test
+%! a = [7 9 7; 0 0 0; 7 9 7; 5 5 5; 1 4 5];
+%! b = [0 0 0; 5 5 5];
+%! [c, ia] = setdiff (a, b, "rows", "legacy");
+%! assert (c, [1, 4 ,5; 7, 9 7]);
+%! assert (ia, [5; 3]);
+
+## Output orientation with "legacy" option 
+%!assert (size (setdiff ([1:5], [2:3], "legacy")), [1, 3])
+%!assert (size (setdiff ([1:5]', [2:3], "legacy")), [1, 3])
+%!assert (size (setdiff ([1:5], [2:3]', "legacy")), [1, 3])
+%!assert (size (setdiff ([1:5]', [2:3]', "legacy")), [3, 1])