Mathematica Advanced I
本文的nb文件GayHub仓库地址,望各位不要吝啬小心心,给咱的小仓库点点小星星
https://github.com/zongpingding/Mathematica
1. 引入
先来看一段代码(代码来源:如何用最简单的代码说明Mathematica里面的各个水平层次?)
1 | |
这段代码中的
1 | |
都是一些啥玩意?你肯能还会在其他的代码中看到另外的一些乱码比如:
1 | |
其实这些就是MMA里面函数的简写:这里我予以说明, 详情肯定是的参考官方文档了
2. 说明
2.1 符号说明
| 符号 | 原始形式 | 含义 |
|---|---|---|
| // | 函数的后缀表达式 | Head[1] <=> 1//Head |
| ~ | 函数的中缀表达式 | Plus[1, 1] <=> 1~Plus~1 |
| := | 延迟赋值(可以实时更新) | 自定义函数: f[x_] := x+1; |
| == | 相等关系 | x^2 - 2x + 1 == 0 (一个方程) |
| = | 赋值符号 | a = 2 |
| @ | 函数映射(作用) | f[2] <=> f@2 |
| @@ | Apply-应用, 更换头部 | Apply[f, {1, 2}] <=> f@@{1, 2} |
| @@@ | Apply 应用在第一层的简写 | Apply[f, {1, 2}, {1}] <=> f@@@{1, 2} |
| /; | Condition (/;)(条件) | {6, -7, 3, 2, -1, -2} /. x_ /; x < 0 -> w => {6, w, 3, 2, w, w} |
| /. | 把某一个表达是按照规则替换 | {x, x^2, y, z} /. x -> 1=> {1, 1, y, z} |
| /@ | Map-映射,Map默认作用在第0层 | Map[f, 2] <=> f/@2 |
| → | Rule (->)(规则, 这个和我们所说的相等有区别) | {x, x^2, a, b} /. x -> 3 => {3, 9, a, b} |
| # | 隐函数参数中的第一个参数 | #1 <=> # |
| ## | 纯函数的参数序列 | f[x, ##, y]&[a, b, c, d] => f[x, a, b, c, d, y] |
| ##3 | 表示提供给一个纯函数的参数序列,从第 n个参数开始 | f[##2] &[a, b, c, d] => f[b, c, d] |
| #1 | 隐函数中的第一个参数 | #1 + 1&; |
| % | 引用上一次结果 | % |
| %4 | 引用第4次运算结果 | %4 |
| & | 纯(匿名)函数声明 | Function[x, x^2]; <=> #^2&; |
| [[]] | 数组索引 | ls[[1]] (数组的第1个元素) |
还有一个key的概念,#key 选出在关联中对应于"key"的值
1 | |
上述代码的运行结果为:
1 | |
2.2 语法说明
一些语句你可能也看不懂,比如下面的
1 | |
其实这就是操作中层的概念; 还有以下常见的代码片段:
1 | |
或者是下面这个
1 | |
其实这个就是MMA中变量的作用域的概念或者是说生命周期;下面这个例子就是一个比较综合的代码片段,截取自
1 | |
MMA中的 -> 是什么意思啊,为什么不直接使用类似Python中的关键字参数使用=来传参呢?这些种种,我都会在下面予以说明。
3. 高级编程
其实我也远远没有达到高级编程的程度,但是着篇文章的目的就是为了让你能够看明白其他人的代码。一些你不熟悉的函数,查官方文档就行了。下面主要是一些关于常用内置函数和匿名函数操作的演示。当然还有很多很炫的操作在MMA中,多Google一下就知道了,我这里肯定不能全部包括,特别是一些内置函数的速度快慢等,慢慢积累的。
3.1 匿名函数
单参数
1 | |
运行结果
1 | |
多参数
1 | |
运行结果
1 | |
抽象函数
1 | |
运行结果
1 | |
Function函数
1 | |
运行结果
1 | |
3.2 头部/数据类型
就目前而言,我觉得这个头部和这个C语言里面的数据类型是差不多的,当然我觉得MMA里面的用起来更舒服一点。
什么是头部
实际上就是一个表达式的数据类型,比如 List, Integer, Float 等; 我们自定义的函数可以看作是一个头部,所以才有了所谓的 Head函数; 具体写法如下:主要就是一个抽象的单形参函数 f 的使用
1 | |
运行结果
1 | |
替换头部
比如把一个"列表"List的表头替换成Plus,我们就可以对"列表"中的元素求和了; Apply 可用于任何头部,而不仅仅是 List.
1 | |
运行结果
1 | |
抽象头部
1 | |
运行结果
注:SlotSequence (##)(插符序列)
3.3 常见简写
下面就是一些常见的函数简写的使用方法
Map(/@)
Map[f, expr] 或 f/@expr: 将 f 应用到 expr 中第一层的每个元素.
第1个示例
1 | |
运行结果
1 | |
第2个示例
1 | |
运行结果
1 | |
多个参数必须使用 Apply 函数,见下面的说明
Apply(@@)
f@@expr或Apply[f,expr]: 用f替换expr的头部.Apply[f]: 表示Apply的运算符形式,它可以应用于表达式.Apply[f,expr,levelspec]: 替换expr中使用levelspec指定的部分的头部.
第1个示例
1 | |
运行结果
1 | |
第2个示例:具体写法,主要举例了 f 为一个具体的三个形参的函数时的情况
1 | |
运行结果
1 | |
如果要作用于一个多参数组成的列表,就需要使用层这个概念了
3.4 操作的层
为什么我们需要层的概念? 为了解决函数作用于列表的时候告诉程序:
- 列表整体是一个参数
- 列表中的元素为各个参数(传入多个复合函数形参的参数个数)
表达式所带的层对应于需要提取部分的索引号. 像 Map 这样的函数可以在指定的层进行操作,可以简单的认为:跨越的大括号对数 = 层数
引入
为什么要有层的概念呢?我当初刚学这个玩意儿的时候是懵逼的,直到有一天我遇到一个问题:
我定义了一个接受三个参数的函数,然后我有一个坐标点的集合,具体的值如下:
每一个传入后, 都会返回一个具体的实数值。
我不想用循环(或者是Table去做),就想用Apply去做,让它同时返回这样的一个列表。但是我如果直接使用如下的语句:
1 | |
是报错的,说参数不够。
其实当时是受了
Map的影响,因为Map这样就不会报错
然后就深入Apply,就了解到了有层这个概念;其实按照我的理解,层的作用如下(使用上面的例子):
- 你告诉函数你的形参列表到底是谁,是最外层(第0层)的那个大列表(此时传入的形参数目为1,就是最大的那个列表)
- 还是里面第1层的那三个列表(此时传入的型参数目为1,是大列表中的每个小列表,但是F会在第一层遍历这个具有三个元素的大列表)
所以这就是层的作用,还是挺简单的.
所以你要真正地搞懂某个东西,也许只有你需要用到它时
Map
第1层
1 | |
运行结果
1 | |
第2层
1 | |
运行结果
1 | |
Apply
第0层
也就是直接把列表中的所有元素作为形参,作用得到一个一维的表达式,,给出一个简单的例子.
1 | |
运行结果
1 | |
第1层
在第一层应用(此时有一个缩写,为@@@), 也就是把列表中的每一个元素作为函数每一次作用的形参,作用得到的维度等于列表的维度
1 | |
运行结果
1 | |
Map默认在第一层操作Apply默认在第零层操作
@
这个是指普通函数应用,一个简单的示例
1 | |
运行结果
1 | |
多参数匿名函数作用于列表
此时一般不能够用简写的形式, 但是Apply有一个@@@的简写,
1 | |
运行结果
1 | |
3.5 同时作用多层
既然我们可一选择作用在一个层,那么想当然的,我们可以作用于多个层,具体的作用方式就有以下的几种:
1 | |
运行结果
1 | |
向下至层2(层0除外)
1 | |
运行结果
1 | |
层0至2
1 | |
运行结果
1 | |
所有层(从层1)
1 | |
运行结果
1 | |
层0至所有层
1 | |
运行结果
1 | |
函数符合顺序
1 | |
运行结果
1 | |
3.5 一切/随处皆可匿
也就是说,无论在什么地方你都可以使用匿名函数; 若匿名函数多个参数时:使用[]包括。
我们可以把我们原来的简单的语句轻松的改成匿名函数语句,相关的操作可以参见下面的演示:
基本使用
1 | |
运行结果
1 | |
实际案例
示例1
1 | |
运行结果
1 | |
示例2
1 | |
运行结果
1 | |
示例3
1 | |
运行结果
3.6 关联
关联将把键符与其值相关联,(用 -> 输入); 其实和Python中的字典差不多,就是一些键值对组成的一个列表。Python或者是其他语言学的好,理解这个也没有什么难的
基本使用
1 | |
运行结果
1 | |
给出键值
1 | |
运行结果
1 | |
纯函数应用
在纯函数中,#key 选出在关联中对应于"key"的值,一个简单的示例:
1 | |
运行结果
1 | |
3.7 插符序列
##
##表示提供给纯函数的完全的参数序列,## 是 ##1 的一个简短形式,指的是函数的所有参数.
1 | |
运行结果
1 | |
对应于##的原对象是一个Sequence,见下面的案例:
1 | |
运行结果
1 | |
指定参数起始位置
1 | |
运行结果
1 | |
迭代列表插入到一个Table
1 | |
运行结果
4. 常用函数
4.1 Moudle
主要有两种用法:
Module[{x,y,...}, expr]: 指定在expr中出现的符号x, y, ...应被当作局部值.(且不会受到全局变量的影响)Module[{x=x0,...}, expr]: 用来定义x, ...的初始值.
变量的作用域
1 | |
运行结果
1 | |
变量生命周期
1 | |
运行结果
1 | |
4.2 With
用法解释:With[{x=x0, y=y0, ...},expr]: 指定在 expr 中出现的符号 x, y, ... 应当由x=x0, y=y0, ...替换.
备注:With 似乎比 Module 快
基本使用
1 | |
运行结果
1 | |
没有估值
1 | |
运行结果
1 | |
多次替换
1 | |
运行结果
1 | |
4.3 Nest
Nest[f,expr,n]: 返回一个将f作用于 expr 上 n 次后得到的表达式.
1 | |
运行结果
1 | |
4.4 TreeForm
可以使用TreeForm查看Mathematica内部表达式的机构,一个示例:
1 | |
运行结果
5. 结语
有了这些操作,再也不用担心你的队友看得懂你的代码,说你代码写的菜了。你直接怼他:把我代码看懂再说。
还是尽量不要使用太多则会个玩意儿,不然你连你自己的代码都看不明白。
