19.3函数应用

一般来说,函数应该已经考虑到矩阵参数,并且应该以系数化的方式考虑整个矩阵运算。有时,因为各种原因,以这种方式写作似乎很困难或不可能。对于这些情况,Octave提供了将函数应用于数组、数组或结构体的每个元素的函数。

 
B = arrayfun (fcn, A)
B = arrayfun (fcn, A1, A2, …)
[B1, B2, …] = arrayfun (fcn, A, …)
B = arrayfun (…, "UniformOutput", val)
B = arrayfun (…, "ErrorHandler", errfcn)

对数组的每个元素执行一个函数。

这对于不接受数组参数的函数非常有用。如果函数确实接受数组参数,则为较好的直接调用函数。

第一个输入参数fcn可以是字符串、函数句柄、线性函数或匿名函数。输入参数A可以是逻辑数组、数字数组、字符串数组、结构体数组或元胞数组。arrayfun传递的所有元素A单独到函数fcn并收集结果。等效的伪代码是

cls = class (fcn (A(1));
B = zeros (size (A), cls);
for i = 1:numel (A)
  B(i) = fcn (A(i))
endfor

命名函数还可以接受两个以上的输入参数,其中inputarguments作为第三个输入参数A2,第四个输入自变量A2, ... 如果给定多个数组输入参数,则所有输入参数的大小必须相同。例如

arrayfun (@atan2, [1, 0], [0, 1])
     ⇒ [ 1.57080   0.00000 ]

如果参数val在另一个字符串输入参数之后"UniformOutput"已设置true(默认值),然后命名函数fcn必须返回一个元素,然后将该元素连接到返回值,并且该元素的类型为matrix。否则,如果该参数设置为false,然后将输出连接到元胞数组中。例如:

arrayfun (@(x,y) x:y, "abc", "def", "UniformOutput", false)
⇒
   {
     [1,1] = abcd
     [1,2] = bcde
     [1,3] = cdef
   }

如果给定了多个输出参数,则命名函数必须返回预期的返回值数量,例如:

[A, B, C] = arrayfun (@find, [10; 0], "UniformOutput", false)
⇒
A =
{
   [1,1] =  1
   [2,1] = [](0x0)
}
B =
{
   [1,1] =  1
   [2,1] = [](0x0)
}
C =
{
   [1,1] =  10
   [2,1] = [](0x0)
}

如果参数errfcn在另一个字符串输入参数之后"ErrorHandler"是另一个字符串、函数句柄、内联函数或匿名函数,则errfcn在以下情况下定义函数tocallfcn生成错误。函数的定义必须为

function [...] = errfcn (s, ...)

其中有一个附加的输入参数errfcn相对于fcn,从给定s。这是一个包含元素的结构体"identifier", "message""index"分别给出导致错误的数组元素的错误标识符、错误消息和索引。的输出参数的大小errfcn的输出参数必须具有相同的大小fcn,否则将引发真正的错误。例如

function y = ferr (s, x), y = "MyString"; endfunction
arrayfun (@str2num, [1234],
          "UniformOutput", false, "ErrorHandler", @ferr)
⇒
   {
     [1,1] = MyString
   }

详见: spfun, cellfun, structfun.

广告
 
y = spfun (f, S)

计算f (S)的非零元素S.

输入函数f仅应用于输入矩阵的非零元素S其通常是稀疏的。函数f可以作为字符串、函数句柄或内联函数传递。

输出y是与输入具有相同稀疏性结构体的稀疏矩阵S. spfun保留稀疏性结构体,该结构体不同于简单地应用函数f到稀疏矩阵Sf (0) != 0.

用例

稀疏性保留spfun与正常函数应用程序相比

S = pi * speye (2,2)
S =

Compressed Column Sparse (rows = 2, cols = 2, nnz = 2 [50%])

  (1, 1) -> 3.1416
  (2, 2) -> 3.1416

y = spfun (@cos, S)
y =

Compressed Column Sparse (rows = 2, cols = 2, nnz = 2 [50%])

  (1, 1) -> -1
  (2, 2) -> -1

y = cos (S)
y =

Compressed Column Sparse (rows = 2, cols = 2, nnz = 4 [100%])

  (1, 1) -> -1
  (2, 1) -> 1
  (1, 2) -> 1
  (2, 2) -> -1

详见: arrayfun, cellfun, structfun.

广告
 
A = cellfun (@fcn, C)
A = cellfun ("fcn", C)
A = cellfun (fcn, C)
A = cellfun (fcn, C1, C2, …)
[A1, A2, …] = cellfun (…)
A = cellfun (…, "UniformOutput", val)
A = cellfun (…, "ErrorHandler", errfcn)
A = cellfun ('isempty', C)
A = cellfun ('islogical', C)
A = cellfun ('isnumeric', C)
A = cellfun ('isreal', C)
A = cellfun ('length', C)
A = cellfun ('numel', C)
A = cellfun ('prodofsize', C)
A = cellfun ('size', C, dim)
A = cellfun ('isclass', C, class)

评估名为fcn的函数在元胞数组的元素上C.

cellfun接受一个任意的函数fcn,可以是函数名称字符串, 可以是函数句柄,也可以是内联函数。指定 fcn为函数名称字符串是推荐做法,因为在内置函数中快3倍,并且和在m文件中的函数一样快。

cellfun有少数几个函数被特殊编写以提供更高性能(比函数句柄快8倍)。 这些函数只用于当fcn是以字符串形式指定的内置函数,并且只支持最简单的调用格式——没有选项的cellfun('fcn', C)。 如果要使用特定classdef文件的重载版本的函数(例如numel),则不能使用函数名称,必须改用函数句柄,例如@numel

高性能的函数包括:

'isempty'

如果元素为空则返回true

广告
'islogical'

如果元素为逻辑元素则返回true

广告
'isnumeric'

如果元素为数字元素则返回true

广告
'isreal'

如果元素为实数则返回true

广告
'length'

返回数组元素长度的向量。

广告
'ndims'

返回每个元素的维度数。

广告
'numel'
'prodofsize'

返回每个数组元素中包含的元素数。数字是对象在每个单元元素处的尺寸的乘积。

广告
'size'

返回第dim个维度的尺寸

广告
'isclass'

如果元素的类型为class则返回true

广告

C中的元素都传入函数,然后每个函数的结果都收集到输出参数中。函数可以接受多个输入,通过C1, C2等给出输入参数。奇异(1x1)单元格的输入自变量将自动扩展到其他自变量的大小。例如:

cellfun ("atan2", {1, 0}, {0, 1})
     ⇒ [ 1.57080   0.00000 ]

的输出参数数cellfun匹配函数的outputarguments的数量,并且可以大于一。当函数有多个输出时,它们将被收集到的输出参数中cellfun这样地:

function [a, b] = twoouts (x)
  a = x;
  b = x*x;
endfunction
[aa, bb] = cellfun (@twoouts, {1, 2, 3})
     ⇒
        aa =
           1 2 3
        bb =
           1 4 9

请注意,默认情况下,输出参数是与输入参数大小相同的数组。

如果参数"UniformOutput"如果设置为true(默认值),则函数必须返回标量,标量将连接到returnarray中。如果"UniformOutput"如果为false,则输出连接到一个(或多个)元胞数组。例如

cellfun ("lower", {"Foo", "Bar", "FooBar"},
         "UniformOutput", false)
⇒ {"foo", "bar", "foobar"}

参数"ErrorHandler"指定errfcn调用的函数, 如果fcn生成错误。函数的形式是

function [...] = errfcn (s, ...)

其中有一个额外的输入参数errfcn相对于fcn,从给定s。这是一个包含元素的结构体"identifier", "message""index"将错误标识符、错误消息和索引分别提供给导致错误的元素的输入参数。例如

function y = foo (s, x), y = NaN; endfunction
cellfun ("factorial", {-1,2}, "ErrorHandler", @foo)
⇒ [NaN 2]

注意:聪明地用cellfun。这里的cellfun函数是避免循环的有用工具。它经常与匿名函数句柄一起使用;然而,调用匿名函数所涉及的开销与m文件函数的开销相当。将句柄传递给内置函数是错误的,因为解释器不参与内部循环。例如:

C = {...}
v = cellfun (@(x) det (x), C); # compute determinants
v = cellfun (@det, C);         # 40% faster

详见: arrayfun, structfun, spfun.

广告
 
A = structfun (fcn, S)
A = structfun (…, "ErrorHandler", errfcn)
A = structfun (…, "UniformOutput", val)
[A, B, …] = structfun (…)

评估名为的函数name关于结构体的字段S。的字段S传递给函数fcn个别地。

structfun接受任意函数fcn以线性函数、函数句柄或函数名称(在字符串中)的形式。如果是字符串参数,函数必须接受一个名为x,并且它必须返回一个字符串值。如果函数返回多个参数,它们将作为单独的返回变量返回。

如果参数"UniformOutput"如果设置为true(默认值),则函数必须返回一个元素,该元素将连接到返回值中。如果"UniformOutput"如果为false,则输出被放置到与输入结构体具有相同字段名的结构体中。

s.name1 = "John Smith";
s.name2 = "Jill Jones";
structfun (@(x) regexp (x, '(\w+)$', "matches"){1}, s,
           "UniformOutput", false)
  ⇒ scalar structure containing the fields:
       name1 = Smith
       name2 = Jones

给定参数"ErrorHandler", errfcn定义一个函数以在case中调用fcn生成错误。函数的形式是

function [...] = errfcn (se, ...)

其中有一个附加的输入参数errfcn相对于fcn,从给定se。这是一个包含元素的结构体"identifier", "message""index",分别给出导致错误的元素的输入自变量的错误标识符、错误消息和索引。有关如何使用错误处理程序的示例,详见cellfun.

详见: cellfun, arrayfun, spfun.

广告

与之前的建议一致,尽可能使用Octave内置函数以获得最佳性能。此建议尤其适用于上述四个函数。例如,当通过元素将两个数组添加在一起时,可以使用内置加法函数的句柄@plus或定义一个匿名函数@(x,y) x + y但是,该匿名函数比第一种方法慢60%。详见运算符重载,以获取可能用来代替匿名函数的基本函数列表。


版权所有 © 2024-2025 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号-2