1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
## Copyright (C) 2014-2022 Carnë Draug <carandraug@octave.org>
##
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## This program is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; see the file COPYING. If not, see
## <http://www.gnu.org/licenses/>.
## -*- texinfo -*-
## @deftypefn {Function File} {[@var{x}, @var{y}, @dots{}] =} removeExtraNanSeparators (@var{x}, @var{y}, @dots{})
## Remove groups of NaN and leave a single separator.
##
## For any number of vectors, @var{x}, @var{y}, @var{z}, @dots{}, reduce
## groups of contiguous NaNs into a single NaN separator. The vectors must
## all have the same dimensions and the NaNs must be locations. Leading NaNs
## are removed, and trailing NaNs are reduced to one.
##
## @example
## @group
## removeExtraNanSeparators ([NaN NaN 3 4 5 NaN NaN 8 NaN], [NaN NaN 7 6 5 NaN NaN 2 NaN])
## @result{}
## [3 4 5 NaN 8 NaN]
## @result{}
## [7 6 5 NaN 2 NaN]
## @end group
## @end example
##
## @seealso{diff, isnan, isna}
## @end deftypefn
## Author: Carnë Draug <carandraug@octave.org>
function [varargout] = removeExtraNanSeparators (varargin)
if (nargin < 1)
print_usage ();
elseif (! isvector (varargin{1}) || ! size_equal (varargin{:}))
error ("removeExtraNanSeparators: X, Y, Z, ... must be vectors with equal sizes");
endif
## one row per input argument
if (iscolumn (varargin{1}))
ins = cell2mat (varargin)';
else
ins = cell2mat (varargin');
endif
nans = isnan (ins);
if (any (nans(:)))
if (any (any (nans) != all (nans)))
error ("removeExtraNanSeparators: NaN and NA positions must be equal on X, Y, Z, ...");
endif
## This will create a mask that selects the first change from a non-NaN
## into a NaN. If there are leaading NaN it will not identify them but
## it will identify the first of trailing NaNs.
nan_sep = diff ([true nans(1,:)]) == 1;
line_mask = ! nans(1,:) | nan_sep;
full_mask = repmat (line_mask, [nargin 1]);
elems = nnz (line_mask);
outs = reshape (ins(full_mask), [nargin elems]);
if (iscolumn (varargin{1}))
varargout = mat2cell (outs', elems, ones (nargin, 1));
else
varargout = mat2cell (outs, ones (nargin, 1), elems);
endif
else
## there are no NaNs, so give the input back
varargout = varargin;
endif
endfunction
## We remove trailing NaN and leave only one at the end
%!assert (nthargout (1:2, @removeExtraNanSeparators,
%! [NaN NaN 3 4 5 6 NaN NaN], [NaN NaN 4 5 5 7 NaN NaN]),
%! {[ 3 4 5 6 NaN ], [ 4 5 5 7 NaN ]});
## We leave individual NaN in the middle intact
%!assert (nthargout (1:2, @removeExtraNanSeparators,
%! [NaN NaN 3 4 NaN 6 NaN], [NaN NaN 2 4 NaN 3 NaN]),
%! {[ 3 4 NaN 6 NaN], [ 2 4 NaN 3 NaN]});
## We turn a group of NaN into a single separator
%!assert (nthargout (1:2, @removeExtraNanSeparators,
%! [NaN 2 NaN NaN 6 NaN], [NaN 1 NaN NaN 8 NaN]),
%! {[ 2 NaN 6 NaN], [ 1 NaN 8 NaN]});
%!assert (nthargout (1:2, @removeExtraNanSeparators,
%! [1 2 NaN NaN 6 NaN], [8 1 NaN NaN 8 NaN]),
%! {[1 2 NaN 6 NaN], [8 1 NaN 8 NaN]});
## We don't mess up when there's no trailing(s) NaN
%!assert (nthargout (1:2, @removeExtraNanSeparators,
%! [1 2 NaN NaN 6], [8 1 NaN NaN 8]),
%! {[1 2 NaN 6], [8 1 NaN 8]});
## We don't mess up when there's no NaN's at all
%!assert (nthargout (1:2, @removeExtraNanSeparators, 1:9, 1:9), {1:9 1:9})
%!assert (nthargout (1:2, @removeExtraNanSeparators, 9:-1:-9, 9:-1:-9), {9:-1:-9 9:-1:-9})
## We don't mess up for x, y, z, etc
%!assert (nthargout (1:3, @removeExtraNanSeparators,
%! [1 2 NaN NaN 6], [8 1 NaN NaN 8], [5 6 NaN NaN 7]),
%! {[1 2 NaN 6], [8 1 NaN 8], [5 6 NaN 7]});
## We don't mess up when we get column vector instead of row vectors
%!assert (nthargout (1:3, @removeExtraNanSeparators,
%! [1 2 NaN NaN 6]', [8 1 NaN NaN 8]', [5 6 NaN NaN 7]'),
%! {[1 2 NaN 6]', [8 1 NaN 8]', [5 6 NaN 7]'});
%!error <must be vectors> removeExtraNanSeparators (rand (5), rand (5))
%!error <equal sizes> removeExtraNanSeparators (rand (5, 1), rand (6, 1))
%!error <must be vectors> removeExtraNanSeparators (rand (5, 1), rand (5, 1), rand (5))
%!error <equal sizes> removeExtraNanSeparators (rand (5, 1), rand (5, 1), rand (6, 1))
%!error <NaN and NA positions> removeExtraNanSeparators ([NaN NaN 3 4 5 6 NaN], [NaN 2 3 4 5 6 NaN])
%!error <NaN and NA positions> removeExtraNanSeparators ([NaN NaN 3 4 5 6 NaN], [NaN NaN 3 4 5 6 NaN], [NaN 2 3 4 5 6 NaN])
|