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. 结语
有了这些操作,再也不用担心你的队友看得懂你的代码,说你代码写的菜了。你直接怼他:把我代码看懂再说。
还是尽量不要使用太多则会个玩意儿,不然你连你自己的代码都看不明白。