罗兰在MATLAB的艺术

把想法变成MATLAB

请注意

罗兰在MATLAB的艺术已经存档,不会被更新。

介绍与匿名函数函数式编程,第1部分

麦克卢尔塔克是一个应用程序与MathWorks工程师。他帮助我们的客户加快自己的工作有了正确的工具和解决问题的技巧。今天,他会讨论“函数式编程”如何帮助创建简单和强大的MATLAB代码。

内容

我们的目标

我使用一个匿名函数。他们很紧凑,简单的几乎看不见。加上,如果我可以写一个匿名函数做某一件事,我不需要保存函数在一个文件中,这可以节省我从文件杂乱大型项目和不必派人一打文件而不是发送一个干净的脚本。然而,乍一看似乎像匿名函数必须一定是简单的。没有如果……其他的,,可以使用,或任何其他关键字。所以我们怎么可能在匿名函数编写复杂的程序?我们将会看到,它将涉及到函数式编程的一些想法。

本文的目标是展示一些这些技术可以改变我们的工作方式在MATLAB中,允许更多的简洁,同时增加可读性。有三个部分。在第一部分中,我们将介绍创建函数功能和治疗功能的变量(在MATLAB,这意味着函数处理),并从那里,我们将继续实施条件语句(如如果……其他的在匿名函数)。在接下来的部分中,我们将添加递归和执行多条语句在一个匿名函数。在最后一部分中,我们将开发一个循环功能。但是首先,如果“函数处理”或“匿名函数”是新的给你,去看看罗兰的这些想法在她的好介绍以前的职位!

最小和最大的例子

假设我们想写一个函数的最小值和最大值的一组数据,并将结果存储在一个数组。这里有一个第一遍:

min_and_max = @ (x) [min (x) max (x));min_and_max ([3 4 1 6 2])
答6 = 1

我们的min_and_max我们将调用函数数组中x发现,最小值和最大值,将两个结果存储在一个输出数组。清楚了吗?好。但现在让我们更加困难。的最小值马克斯函数都返回两个如果需要输出(最小值或最大值的指数出现在输入数组)。我们的简单min_and_max功能不能得到那些次级输出!我们如何访问它们?考虑这个外形奇特。

[极值,指数]= cellfun (@ f (f) ([3 4 1 6 2]), {@min, @max})
极值= 1 6指数= 3 4

这显然奏效了。最低,1,发生在指数3。最大6发生在指数4,但实际上这条线在做什么?首先,记得cellfun行为。第一个参数是一个函数处理。第二个参数是一个细胞的数组。单元阵列的每个元素作为参数提供函数句柄。大多数时候,细胞阵列的数据,每个数据传递给函数。然而,我们可以把函数处理单元阵列。然后第一个函数(@ f (f) (…))作用于所有其他功能。所以,首先@min是通过的f和输出min ([3 4 1 6 2])存储。然后,@max是通过的f,它的输出存储。

好了,现在我们正在与函数的函数,让我们删除硬编码的(3 4 1 6 2)并编写一个新的min_and_max只需添加一个函数@ (x)前面和改变(3 4 1 6 2)x

min_and_max = @ (x) cellfun (@ (f) f (x), {@min, @max});

我们现在可以使用min_and_max为极值,像以前一样,但是我们也可以指数。

y =兰迪(10 1 10)just_values = min_and_max (y) [~, just_indices] = min_and_max (y)[极值指数]= min_and_max (y)
y = 2 10 10 5 9 2 5 8 10 just_values = 2 just_indices = 1 2极值= 2 10指数= 1 2

可能看起来有点滑稽,但很容易思考,对吧?现在我们让它看起来更好一点。

地图

以上,我们每个函数映射到输入x。更普遍的是,我们可以写一个“地图”功能,一系列的函数映射到输入值。我们将瓦尔单元阵列,这样我们也可以发送多个输入多个函数。这就像我们之前,但重新安排。

fcns地图= @ (val) cellfun (@ f (f) (val {:}), fcns);

看起来这是多么的简单min_and_max(下图),同时访问两个输出。它不仅是短的写比任何其他版本到目前为止,这是更容易阅读,几乎除了一个发生的每个变量或函数名。“地图x最小值马克斯功能”。没有问题。

x = [3 4 1 6 2];[极值,指数]=地图({x}, {@min, @max})
极值= 1 6指数= 3 4

让我们尝试多个输入:

地图({1,2},{@plus、@minus @times})
ans = 3 1 2

如果输出是不同的尺寸吗?我们会写mapc与单元阵列输出(如地图)来处理;它只需要一个额外的参数cellfun说我们的输出大小不均匀。

fcns mapc = @ (val) cellfun (@ f (f) (val {:}), fcns,“UniformOutput”、假);

发送π到多个函数,返回大小不同的数组。第一个输出是一个标量,第二个是一个标量,第三个是一个字符串。

mapc({π},{@ x (x) 2 *,%乘以2@cos,%找到余弦@ (x) sprintf (“x % .5f…”,x)})%返回一个字符串
ans = [6.2832] [1]“x = 3.14159…”

这需要照顾地图现在,我们可以使用在任何地方发送一组输入大量的函数和收集他们的多个输出简短易读的代码。

顺便说一下,写这些在其他功能操作的函数是“函数式编程”风格的一部分,而我们只是皮毛。我们去更深刻的看到我们可以编写一个函数来从列表中选择函数应用的功能。

内联条件

有时一个匿名函数可能需要一个条件,就像如果其他……。然而,正常的MATLAB程序流语法不允许这样的语句在匿名函数。希望它不会丢失。我们可以实现一个“内联”一行:

iif = @(变长度输入宗量)变长度输入宗量{2 *找到([变长度输入宗量{1:2:结束}],1,“第一”})();

好了,这看起来非常奇怪,所以在我们讨论它是如何工作的,看一看是多么容易使用:

着干活,out2,……]= iif(如果这个,然后运行这个,…如果这事,然后运行这个,……别的,然后运行这个);

所有的“如果”条件应该评估真或假。旁边的“然后运行这个“行动第一次真正的执行状况。没有执行其他操作!例如,我们可以用这个安全标准化函数做如下:

  • 如果不是所有的值x是有限的,抛出一个错误。
  • 如果所有的值x等于0,返回0。
  • 其他的,还x /规范(x)

这是下面的实现。注意@ ()前面的动作。这意味着,“不要做这个动作,但是请参考这一行动”。也就是说,我们通过的代码片断国际金融协会函数作为参数。通过这种方式,我们不做三件事;我们只单一情况下我们需要行动。

= @正常化(x) iif (~ (isfinite (x)), @()错误(“一定是有限的!”),所有(x = = 0), @() 0(大小(x)),真的,@ ()x /规范(x));

测试名义条件。

正常化((1 1 0))
ans = 0.70711 - 0.70711 0

用非谓语形式的输入测试错误条件。

试一试正常化([0正2]),呃,disp (err.message);结束
必须是有限的!

测试全0条件。

正常化([0 0 0))
ans = 0 0 0

易于使用,对吗?我们已经实现了如果……其他的不需要实际的行为如果其他的在任何地方!所以现在是时候看看这个东西是如何工作的。

首先,国际金融协会函数接受任意数量的参数,谢谢变长度输入宗量。这些参数将条件1(真或假),行动1(函数),条件2,行动2,等。首先,国际金融协会函数选择的所有条件(奇数编号的项目变长度输入宗量)通过[变长度输入宗量{1:2}结束):。为我们的安全规范,这将返回:

[~ (isfinite (x)), (x = = 0),真的)

接下来,它发现的索引真正的价值在这些条件找到(…,1,“第一”)。例如,如果~所有(isfinite (x)),但所有(x = = 0)真正的,该指数将是2。

执行的偶数项的操作变长度输入宗量,所以我们这一指数乘以2的指数进行的动作。最后,我们通过添加执行行动()在最后,

变长度输入宗量{…}()

你那里发生了什么吗?我们通过小纸片代码作为输入国际金融协会函数。功能作为参数。明白为什么这是称为“功能性”编程?我承认它看起来奇怪,但一旦你看到它,这种模式很难忘记。

好吧,今天就到这里。以下是我们今天开发的功能。

iif = @(变长度输入宗量)变长度输入宗量{2 *找到([变长度输入宗量{1:2:结束}],1,“第一”})();fcns地图= @ (val) cellfun (@ f (f) (val {:}), fcns);fcns mapc = @ (val) cellfun (@ f (f) (val {:}), fcns,“UniformOutput”、假);

这些也可以找到在这里作为常规MATLAB函数实现,可以保存路径。

未完待续

在下一篇文章中,我们将构建在这些使递归和匿名函数执行多条语句。与此同时,有多种方法来完成内联。例如,我见过一个非常简短的三元运算符在我们论坛在过去。我很好奇其他实现人可能认为这种类型的行为,所以请建议在这里




发表与MATLAB®R2012b


评论

留下你的评论,请点击在这里MathWorks账户登录或创建一个新的。