# HG changeset patch # User Thomas Treichl # Date 1217537669 -7200 # Node ID bdb0a5aea9f26552c5f3039c14bcbf1ae4d2a829 # Parent d750feaefa8e677bc71e1d559ee5e0629b85e230 Minor bug fixes, update help text and tests diff -r d750feaefa8e -r bdb0a5aea9f2 scripts/ChangeLog --- a/scripts/ChangeLog Fri Nov 14 08:12:55 2008 -0500 +++ b/scripts/ChangeLog Thu Jul 31 22:54:29 2008 +0200 @@ -640,6 +640,10 @@ * strings/strtok.m: Include TAB, LF, VT, FF, and CR in default list of delim characters. Update tests. +2008-07-29 Thomas Treichl + + * general/arrayfun.m: Minor bug fixes, update help text and tests + 2008-07-29 John W. Eaton * plot/axis.m (__get_tight_lims__): Use strcat instead of []. diff -r d750feaefa8e -r bdb0a5aea9f2 scripts/general/arrayfun.m --- a/scripts/general/arrayfun.m Fri Nov 14 08:12:55 2008 -0500 +++ b/scripts/general/arrayfun.m Thu Jul 31 22:54:29 2008 +0200 @@ -1,4 +1,4 @@ -## Copyright (C) 2006, 2007 Bill Denney +## Copyright (C) 2006, 2007, 2008 Bill Denney ## ## This file is part of Octave. ## @@ -17,17 +17,114 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {@var{a} =} arrayfun (@var{name}, @var{c}) -## @deftypefnx {Function File} {@var{a} =} arrayfun (@var{func}, @var{c}) -## @deftypefnx {Function File} {@var{a} =} arrayfun (@var{func}, @var{c}, @var{d}) -## @deftypefnx {Function File} {@var{a} =} arrayfun (@var{func}, @var{c}, @var{options}) -## @deftypefnx {Function File} {[@var{a}, @var{b}, @dots{}] =} arrayfun (@var{func}, @var{c}, @dots{}) +## @deftypefn {Function File} {} arrayfun (@var{func}, @var{a}) +## @deftypefnx {Function File} {@var{x} =} arrayfun (@var{func}, @var{a}) +## @deftypefnx {Function File} {@var{x} =} arrayfun (@var{func}, @var{a}, @var{b}, @dots{}) +## @deftypefnx {Function File} {[@var{x}, @var{y}, @dots{}] =} arrayfun (@var{func}, @var{a}, @dots{}) +## @deftypefnx {Function File} {} arrayfun (@dots{}, "UniformOutput", @var{val}) +## @deftypefnx {Function File} {} arrayfun (@dots{}, "ErrorHandler", @var{errfunc}) +## ## Execute a function on each element of an array. This is useful for ## functions that do not accept array arguments. If the function does ## accept array arguments it is better to call the function directly. ## -## See @code{cellfun} for complete usage instructions. -## @seealso{cellfun} +## The first input argument @var{func} can be a string, a function +## handle, an inline function or an anonymous function. The input +## argument @var{a} can be a logic array, a numeric array, a string +## array, a structure array or a cell array. By a call of the function +## @command{arrayfun} all elements of @var{a} are passed on to the named +## function @var{func} individually. +## +## The named function can also take more than two input arguments, with +## the input arguments given as third input argument @var{b}, fourth +## input argument @var{c}, @dots{} If given more than one array input +## argument then all input arguments must have the same sizes, for +## example +## +## @example +## @group +## arrayfun (@@atan2, [1, 0], [0, 1]) +## @result{} ans = [1.5708 0.0000] +## @end group +## @end example +## +## If the parameter @var{val} after a further string input argument +## "UniformOutput" is set @code{true} (the default), then the named +## function @var{func} must return a single element which then will be +## concatenated into the return value and is of type matrix. Otherwise, +## if that parameter is set to @code{false}, then the outputs are +## concatenated in a cell array. For example +## +## @example +## @group +## arrayfun (@@(x,y) x:y, "abc", "def", "UniformOutput", false) +## @result{} ans = +## @{ +## [1,1] = abcd +## [1,2] = bcde +## [1,3] = cdef +## @} +## @end group +## @end example +## +## If more than one output arguments are given then the named function +## must return the number of return values that also are expected, for +## example +## +## @example +## @group +## [A, B, C] = arrayfun (@@find, [10; 0], "UniformOutput", false) +## @result{} +## A = +## @{ +## [1,1] = 1 +## [2,1] = [](0x0) +## @} +## B = +## @{ +## [1,1] = 1 +## [2,1] = [](0x0) +## @} +## C = +## @{ +## [1,1] = 10 +## [2,1] = [](0x0) +## @} +## @end group +## @end example +## +## If the parameter @var{errfunc} after a further string input argument +## "ErrorHandler" is another string, a function handle, an inline +## function or an anonymous function, then @var{errfunc} defines a +## function to call in the case that @var{func} generates an error. +## The definition of the function must be of the form +## +## @example +## function [@dots{}] = errfunc (@var{s}, @dots{}) +## @end example +## +## where there is an additional input argument to @var{errfunc} +## relative to @var{func}, given by @var{s}. This is a structure with +## the elements "identifier", "message" and "index", giving +## respectively the error identifier, the error message and the index of +## the array elements that caused the error. The size of the output +## argument of @var{errfunc} must have the same size as the output +## argument of @var{func}, otherwise a real error is thrown. For +## example +## +## @example +## @group +## function y = ferr (s, x), y = "MyString"; endfunction +## arrayfun (@@str2num, [1234], \ +## "UniformOutput", false, "ErrorHandler", @@ferr) +## @result{} ans = +## @{ +## [1,1] = MyString +## @} +## @end group +## @end example +## +## @seealso{cellfun, spfun, structfun} ## @end deftypefn ## Author: Bill Denney @@ -45,20 +142,20 @@ m2cargs{2} = ones (size (varargin{1}, 2), 1); cfarg{1} = mat2cell (varargin{1}, m2cargs{:}); stillmatches = true; - idx = 1; - while (stillmatches && idx < numel (varargin)) + idx = 1; len = length (varargin); + while (stillmatches && idx < len) idx++; thissize = size (varargin{idx}); if (numel (thissize) == numel (sizetomatch) - && all (thissize == sizetomatch)) + && all (thissize == sizetomatch)) if (ischar (varargin{idx}) - && (strcmpi (varargin{idx}, "UniformOutput") - || strcmpi (varargin{idx}, "ErrorHandler"))) - ## Catch these strings just in case they happen to be the same - ## size as the other input. - stillmatches = false; + && (strcmpi (varargin{idx}, "UniformOutput") + || strcmpi (varargin{idx}, "ErrorHandler"))) + ## Catch these strings just in case they happen to be the same + ## size as the other input. + stillmatches = false; else - cfarg{idx} = mat2cell (varargin{idx}, m2cargs{:}); + cfarg{idx} = mat2cell (varargin{idx}, m2cargs{:}); endif else stillmatches = false; @@ -66,10 +163,190 @@ endwhile varargout = cell (max ([nargout, 1]), 1); - [varargout{:}] = cellfun (func, cfarg{:}, varargin{idx+1:numel(varargin)}); + if (idx >= len) + [varargout{:}] = cellfun (func, cfarg{:}); + else + [varargout{:}] = cellfun (func, cfarg{:}, varargin{idx:len}); + end endfunction +%% Test function to check the "Errorhandler" option +%!function [z] = arrayfunerror (S, varargin) +%! z = S; +%! endfunction +%% First input argument can be a string, an inline function, a +%% function_handle or an anonymous function %!test -%! fun = @(x,y) 2*x+y; -%! A = [1,2;3,4]; -%! assert(arrayfun(fun,A,A),fun(A,A)) +%! arrayfun (@isequal, [false, true], [true, true]); %% No output argument +%!error +%! arrayfun (@isequal); %% One or less input arguments +%!test +%! A = arrayfun ("isequal", [false, true], [true, true]); +%! assert (A, [false, true]); +%!test +%! A = arrayfun (inline ("(x == y)", "x", "y"), [false, true], [true, true]); +%! assert (A, [false, true]); +%!test +%! A = arrayfun (@isequal, [false, true], [true, true]); +%! assert (A, [false, true]); +%!test +%! A = arrayfun (@(x,y) isequal(x,y), [false, true], [true, true]); +%! assert (A, [false, true]); + +%% Number of input and output arguments may be greater than one +%#!test +%! A = arrayfun (@(x) islogical (x), false); +%! assert (A, true); +%!test +%! A = arrayfun (@(x,y,z) x + y + z, [1, 1, 1], [2, 2, 2], [3, 4, 5]); +%! assert (A, [6, 7, 8], 1e-16); +%!test %% Two input arguments of different types +%! A = arrayfun (@(x,y) islogical (x) && ischar (y), false, "a"); +%! assert (A, true); +%!test %% Pass another variable to the anonymous function +%! y = true; A = arrayfun (@(x) islogical (x && y), false); +%! assert (A, true); +%!test %% Three ouptut arguments of different type +%! [A, B, C] = arrayfun (@find, [10, 11; 0, 12], "UniformOutput", false); +%! assert (isequal (A, {true, true; [], true})); +%! assert (isequal (B, {true, true; [], true})); +%! assert (isequal (C, {10, 11; [], 12})); + +%% Input arguments can be of type logical +%!test +%! A = arrayfun (@(x,y) x == y, [false, true], [true, true]); +%! assert (A, [false, true]); +%!test +%! A = arrayfun (@(x,y) x == y, [false; true], [true; true], "UniformOutput", true); +%! assert (A, [false; true]); +%!test +%! A = arrayfun (@(x) x, [false, true, false, true], "UniformOutput", false); +%! assert (A, {false, true, false, true}); +%!test %% Three ouptut arguments of same type +%! [A, B, C] = arrayfun (@find, [true, false; false, true], "UniformOutput", false); +%! assert (isequal (A, {true, []; [], true})); +%! assert (isequal (B, {true, []; [], true})); +%! assert (isequal (C, {true, []; [], true})); +%!test +%! A = arrayfun (@(x,y) array2str (x,y), true, true, "ErrorHandler", @arrayfunerror); +%! assert (isfield (A, "identifier"), true); +%! assert (isfield (A, "message"), true); +%! assert (isfield (A, "index"), true); +%! assert (isempty (A.message), false); +%! assert (A.index, 1); +%!test %% Overwriting setting of "UniformOutput" true +%! A = arrayfun (@(x,y) array2str (x,y), true, true, \ +%! "UniformOutput", true, "ErrorHandler", @arrayfunerror); +%! assert (isfield (A, "identifier"), true); +%! assert (isfield (A, "message"), true); +%! assert (isfield (A, "index"), true); +%! assert (isempty (A.message), false); +%! assert (A.index, 1); + +%% Input arguments can be of type numeric +%!test +%! A = arrayfun (@(x,y) x>y, [1.1, 4.2], [3.1, 2+6*i]); +%! assert (A, [false, true]); +%!test +%! A = arrayfun (@(x,y) x>y, [1.1, 4.2; 2, 4], [3.1, 2; 2, 4+2*i], "UniformOutput", true); +%! assert (A, [false, true; false, false]); +%!test +%! A = arrayfun (@(x,y) x:y, [1.1, 4], [3.1, 6], "UniformOutput", false); +%! assert (isequal (A{1}, [1.1, 2.1, 3.1])); +%! assert (isequal (A{2}, [4, 5, 6])); +%!test %% Three ouptut arguments of different type +%! [A, B, C] = arrayfun (@find, [10, 11; 0, 12], "UniformOutput", false); +%! assert (isequal (A, {true, true; [], true})); +%! assert (isequal (B, {true, true; [], true})); +%! assert (isequal (C, {10, 11; [], 12})); +%!test +%! A = arrayfun (@(x,y) array2str(x,y), {1.1, 4}, {3.1, 6}, "ErrorHandler", @arrayfunerror); +%! B = isfield (A(1), "message") && isfield (A(1), "index"); +%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]); +%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]); +%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]); +%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]); +%! assert ([A(1).index, A(2).index], [1, 2]); +%!test %% Overwriting setting of "UniformOutput" true +%! A = arrayfun (@(x,y) array2str(x,y), {1.1, 4}, {3.1, 6}, \ +%! "UniformOutput", true, "ErrorHandler", @arrayfunerror); +%! B = isfield (A(1), "message") && isfield (A(1), "index"); +%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]); +%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]); +%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]); +%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]); +%! assert ([A(1).index, A(2).index], [1, 2]); + +%% Input arguments can be of type character or strings +%!test +%! A = arrayfun (@(x,y) x>y, ["ad", "c", "ghi"], ["cc", "d", "fgh"]); +%! assert (A, [false, true, false, true, true, true]); +%!test +%! A = arrayfun (@(x,y) x>y, ["a"; "f"], ["c"; "d"], "UniformOutput", true); +%! assert (A, [false; true]); +%!test +%! A = arrayfun (@(x,y) x:y, ["a", "d"], ["c", "f"], "UniformOutput", false); +%! assert (A, {"abc", "def"}); +%! %#!test +%! A = arrayfun (@(x,y) cell2str(x,y), ["a", "d"], ["c", "f"], "ErrorHandler", @arrayfunerror); +%! B = isfield (A(1), "identifier") && isfield (A(1), "message") && isfield (A(1), "index"); +%! assert (B, true); + +%% Input arguments can be of type structure +%!test +%! a = struct ("a", 1.1, "b", 4.2); b = struct ("a", 3.1, "b", 2); +%! A = arrayfun (@(x,y) (x.a < y.a) && (x.b > y.b), a, b); +%! assert (A, true); +%!test +%! a = struct ("a", 1.1, "b", 4.2); b = struct ("a", 3.1, "b", 2); +%! A = arrayfun (@(x,y) (x.a < y.a) && (x.b > y.b), a, b, "UniformOutput", true); +%! assert (A, true); +%!test +%! a = struct ("a", 1.1, "b", 4.2); b = struct ("a", 3.1, "b", 2); +%! A = arrayfun (@(x,y) x.a:y.a, a, b, "UniformOutput", false); +%! assert (isequal (A, {[1.1, 2.1, 3.1]})); +%!test +%! A = arrayfun (@(x) mat2str(x), "a", "ErrorHandler", @arrayfunerror); +%! assert (isfield (A, "identifier"), true); +%! assert (isfield (A, "message"), true); +%! assert (isfield (A, "index"), true); +%! assert (isempty (A.message), false); +%! assert (A.index, 1); +%!test %% Overwriting setting of "UniformOutput" true +%! A = arrayfun (@(x) mat2str(x), "a", "UniformOutput", true, \ +%! "ErrorHandler", @arrayfunerror); +%! assert (isfield (A, "identifier"), true); +%! assert (isfield (A, "message"), true); +%! assert (isfield (A, "index"), true); +%! assert (isempty (A.message), false); +%! assert (A.index, 1); + +%% Input arguments can be of type cell array +%!test +%! A = arrayfun (@(x,y) x{1} < y{1}, {1.1, 4.2}, {3.1, 2}); +%! assert (A, [true, false]); +%!test +%! A = arrayfun (@(x,y) x{1} < y{1}, {1.1; 4.2}, {3.1; 2}, "UniformOutput", true); +%! assert (A, [true; false]); +%!test +%! A = arrayfun (@(x,y) x{1} < y{1}, {1.1, 4.2}, {3.1, 2}, "UniformOutput", false); +%! assert (A, {true, false}); +%!test +%! A = arrayfun (@(x,y) num2str(x,y), {1.1, 4.2}, {3.1, 2}, "ErrorHandler", @arrayfunerror); +%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]); +%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]); +%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]); +%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]); +%! assert ([A(1).index, A(2).index], [1, 2]); +%!test +%! A = arrayfun (@(x,y) num2str(x,y), {1.1, 4.2}, {3.1, 2}, \ +%! "UniformOutput", true, "ErrorHandler", @arrayfunerror); +%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]); +%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]); +%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]); +%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]); +%! assert ([A(1).index, A(2).index], [1, 2]); + +## Local Variables: *** +## mode: octave *** +## End: ***