1######################################################################## 2## 3## Copyright (C) 2007-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {} structfun (@var{func}, @var{S}) 28## @deftypefnx {} {[@var{A}, @dots{}] =} structfun (@dots{}) 29## @deftypefnx {} {} structfun (@dots{}, "ErrorHandler", @var{errfunc}) 30## @deftypefnx {} {} structfun (@dots{}, "UniformOutput", @var{val}) 31## 32## Evaluate the function named @var{name} on the fields of the structure 33## @var{S}. The fields of @var{S} are passed to the function @var{func} 34## individually. 35## 36## @code{structfun} accepts an arbitrary function @var{func} in the form of an 37## inline function, function handle, or the name of a function (in a character 38## string). In the case of a character string argument, the function must 39## accept a single argument named @var{x}, and it must return a string value. 40## If the function returns more than one argument, they are returned as 41## separate output variables. 42## 43## If the parameter @qcode{"UniformOutput"} is set to true (the default), then 44## the function must return a single element which will be concatenated into 45## the return value. If @qcode{"UniformOutput"} is false, the outputs are 46## placed into a structure with the same fieldnames as the input structure. 47## 48## @example 49## @group 50## s.name1 = "John Smith"; 51## s.name2 = "Jill Jones"; 52## structfun (@@(x) regexp (x, '(\w+)$', "matches")@{1@}, s, 53## "UniformOutput", false) 54## @result{} scalar structure containing the fields: 55## name1 = Smith 56## name2 = Jones 57## @end group 58## @end example 59## 60## Given the parameter @qcode{"ErrorHandler"}, @var{errfunc} defines a function 61## to call in case @var{func} generates an error. The form of the function is 62## 63## @example 64## function [@dots{}] = errfunc (@var{se}, @dots{}) 65## @end example 66## 67## @noindent 68## where there is an additional input argument to @var{errfunc} relative to 69## @var{func}, given by @nospell{@var{se}}. This is a structure with the 70## elements @qcode{"identifier"}, @qcode{"message"} and @qcode{"index"}, 71## giving respectively the error identifier, the error message, and the index 72## into the input arguments of the element that caused the error. For an 73## example on how to use an error handler, @pxref{XREFcellfun,,cellfun}. 74## 75## @seealso{cellfun, arrayfun, spfun} 76## @end deftypefn 77 78function varargout = structfun (func, S, varargin) 79 80 if (nargin < 2) 81 print_usage (); 82 endif 83 84 nargs = length (varargin); 85 86 recognized_opts = {"UniformOutput", "ErrorHandler"}; 87 uo_str = recognized_opts{1}; 88 89 uniform_output = true; 90 91 while (nargs >= 2) 92 opt_match = strcmpi (varargin{nargs-1}, recognized_opts); 93 if (opt_match(1)) 94 uniform_output = varargin{nargs}; 95 endif 96 if (any (opt_match)) 97 nargs -= 2; 98 else 99 break; 100 endif 101 endwhile 102 103 if (nargs > 0) 104 error ("structfun: invalid options"); 105 endif 106 107 varargout = cell (max ([nargout, 1]), 1); 108 [varargout{:}] = cellfun (func, struct2cell (S), varargin{:}); 109 110 if (! uniform_output) 111 varargout = cellfun ("cell2struct", varargout, {fieldnames(S)}, {1}, ... 112 uo_str, false); 113 endif 114 115endfunction 116 117 118%!test 119%! s.name1 = "John Smith"; 120%! s.name2 = "Jill Jones"; 121%! l.name1 = "Smith"; 122%! l.name2 = "Jones"; 123%! o = structfun (@(x) regexp (x, '(\w+)$', "matches"){1}, s, 124%! "UniformOutput", false); 125%! assert (o, l); 126 127%!function [a, b] = __twoouts (x) 128%! a = x + x; 129%! b = x * x; 130%!endfunction 131 132%!test 133%! s = struct ("a", {1, 2, 3}, "b", {4, 5, 6}); 134%! c(1:2, 1, 1) = [2; 8]; 135%! c(1:2, 1, 2) = [4; 10]; 136%! c(1:2, 1, 3) = [6; 12]; 137%! d(1:2, 1, 1) = [1; 16]; 138%! d(1:2, 1, 2) = [4; 25]; 139%! d(1:2, 1, 3) = [9; 36]; 140%! [aa, bb] = structfun (@__twoouts, s); 141%! assert (aa, c); 142%! assert (bb, d); 143 144%!test 145%! s = struct ("a", {1, 2, 3}, "b", {4, 5, 6}); 146%! c = struct ("a", {2, 4, 6}, "b", {8, 10, 12}); 147%! d = struct ("a", {1, 4, 9}, "b", {16, 25, 36}); 148%! [aa, bb] = structfun (@__twoouts, s, "UniformOutput", false); 149%! assert (aa, c); 150%! assert (bb, d); 151