changeset 23349:4f07b4770eec

orderfields.m: recode algorithm to halve running time (bug #50688). * orderfields.m: Switch to algorithm which uses 1) struct2cell, 2) permute cell indices to perform sort, 3) cell2struct. Add additional BIST test for incorrect second input.
author Guillaume Flandin
date Wed, 05 Apr 2017 11:58:21 -0700
parents 5ab7192f91d8
children 0f18524973eb
files scripts/miscellaneous/orderfields.m
diffstat 1 files changed, 33 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/miscellaneous/orderfields.m	Wed Apr 05 10:55:35 2017 -0700
+++ b/scripts/miscellaneous/orderfields.m	Wed Apr 05 11:58:21 2017 -0700
@@ -106,79 +106,58 @@
 
   if (nargin < 1 || nargin > 2)
     print_usage ();
-  elseif (! isstruct (s1))
+  endif
+
+  if (! isstruct (s1))
     error ("orderfields: S1 must be a struct");
   endif
 
+  names = fieldnames (s1);
+
   if (nargin == 1)
     ## One structure: return the fields in alphabetical order.
-    if (isstruct (s1))
-      names = sort (fieldnames (s1));
-    endif
+    [~, p] = sort (names);
   elseif (nargin == 2)
+
     if (isstruct (s2))
       ## Two structures: return the fields in the order of s2.
-      names = fieldnames (s2);
-      if (! isequal (sort (fieldnames (s1)), sort (names)))
+      names2 = fieldnames (s2);
+      [ns1, idx1] = sort (names);
+      [ns2, idx2] = sort (names2);
+      if (! isequal (ns1, ns2))
         error ("orderfields: structures S1 and S2 do not have the same fields");
       endif
+      p = idx1(idx2);
+
     elseif (iscellstr (s2))
       ## A structure and a list of fields: order by the list of fields.
-      t1 = sort (fieldnames (s1));
-      t2 = sort (s2(:));
-      if (! isequal (t1, t2))
+      names2 = s2(:);
+      [ns1, idx1] = sort (names);
+      [ns2, idx2] = sort (names2);
+      if (! isequal (ns1, ns2))
         error ("orderfields: CELLSTR list does not match structure fields");
       endif
-      names = s2;
-    elseif (isvector (s2))
+      p = idx1(idx2);
+
+    elseif (isnumeric (s2))
       ## A structure and a permutation vector: permute the order of s1.
-      names = fieldnames (s1);
-      t1 = 1:numel (names);
-      t2 = sort (s2);
-      t2 = t2(:)';
-      if (! isequal (t1, t2))
+      p = s2(:);
+      if (! isequal (sort (p), (1:numel (names)).'))
         error ("orderfields: invalid permutation vector P");
       endif
-      names = names(s2);
+
     else
       error ("orderfields: second argument must be structure, cellstr, or permutation vector");
     endif
   endif
 
-  ## Corner case of empty struct
-  if (isempty (names))
-    sout = struct ();
-    p = [];
-  endif
-
-  ## Find permutation vector which converts the original name order
-  ## into the new name order.  Note: could save a couple of sorts
-  ## in some cases, but performance isn't critical.
-
-  if (nargout == 2)
-    [~, oldidx] = sort (fieldnames (s1));
-    [~, newidx] = sort (names);
-    p = oldidx(newidx);
-  endif
-
   ## Permute the names in the structure.
-  if (isempty (s1))
-    ## Corner case of empty structure.  Still need to re-order fields.
-    args = cell (1, 2 * numel (names));
-    args(1:2:end) = names;
-    args(2:2:end) = {[]};
-    sout = struct (args{:});
-    ## inherit dimensions
-    sout = resize (sout, size (s1));
-  else
-    n = numel (s1);
-    for i = 1:numel (names)
-      el = names{i};
-      [sout(1:n).(el)] = s1(:).(el);
-    endfor
-    ## inherit dimensions
-    sout = reshape (sout, size (s1));
-  endif
+  names = names(p);
+  C = struct2cell (s1);
+  C = C(p,:);
+  sout = cell2struct (C, names);
+  ## Inherit dimensions.
+  sout = reshape (sout, size (s1));
 
 endfunction
 
@@ -239,6 +218,9 @@
 %!error <invalid permutation vector P>
 %! s1.a = 1;
 %! orderfields (s1, [2 1]);
+%!error <invalid permutation vector P>
+%! s1.a = 1;
+%! orderfields (s1, ones (2,2));
 %!error <second argument must be structure, cellstr, or permutation vector>
 %! s1.a = 1;
-%! orderfields (s1, ones (2,2));
+%! orderfields (s1, "foobar");