2、表操做 返回目录页
一、引言
二、表的建立与表的测量
Range Table Length Dimensions
三、对表中元素的处理
Position Part Take Drop Delete First/Last/Rest Select/Reverse/Sort
RotateLeft/RotateRight Flatten Partiton Transpose Append/Prepend Insert/ReplacePart
四、对多个表的处理
Join/Union Complement/Intersection
五、高阶函数
Map/MapThread Outer Apply
六、函数对表的重复做用
Nest/NestList Fold/FoldList
七、字符串和字符
StringLength... Characters/StringJoin ToCharacterCode/FromCharacterCode
html
----------------------------------------------------程序员
一、引言
上面能够看到,表操做函数有几十个。如今的MMA表操做函数,已经上千了。
最经常使用的,也就那么几十个,并很少。
咱们熟悉MMA的函数,当从表操做函数开始。缘由有几个:
表是MMA中最经常使用的数据结构。
表操做函数是最经常使用的MMA函数。
咱们学英语,要先很是熟悉最经常使用的220个单词(Sight Words),同样,学MMA,要先熟悉这几十个表操做函数。
除此以外,还有个秘密缘由,在本章的最后。若是急着想知道,就戳吧。
MMA中表之强大,在于表中能够听任何表达式。
List[2.4, dog, Sin, "read", {5, 3}, Pi, {}]
{}是空表,empty list。
List[2.4, dog, Sin, "read", {5, 3}, Pi, {}] // TreeForm
MMA中表之强大,更在于,表能够是多维的。这个维数,能够从树形结构上去理解。
----------------------------------------------------
二、表的建立与表的测量
表的建立,只有两个函数。表的测量,也只有两个函数。
表的建立的两个函数是:Range、Table
Range[1, 10, 2]
得:{1, 3, 5, 7, 9}
三个参数分别是:最小、最大、步长。至关于在构建等差数列。
Table[i, {i, 1, 10, 2}]
结果与上面同样的。能够看到,{i, 1, 10, 2}中的含义:变量、最小、最大、步长。
第一个参数i位置,能够听任何表达式。这个表达式能够与i有关,也能够与i无关。
函数设计到这里,彷佛差很少了。但MMA展现了灵活性:不少参数是能够省略的。
A、若是步长为1,能够省略不写。
B、若是起始最小值为1,能够省略不写。
C、若是Table中的表达式与变量i无关,变量i能够省略不写。
D、终止最大值,永远不能够省略。
Range[5]
Table[2i,{i,5}]
Table["哈",{5}]
有没有找到好玩的感受?MMA这是在偷工减料啊。。不过,不少程序员很喜欢这种偷工减料,由于很好用,并且代码很简洁。
Table[i + j, {j, 1, 4}, {i, 1, 2}]
Table[i + j, {j, 1, 4}, {i, 1, 2}] // MatrixForm
Table[i + j, {j, 1, 4}, {i, 1, 2}] // TableForm
Table函数还支持多重循环。外层循环变量(j)要先写。也就是说,循环变量在Table参数中的顺序是有讲究的。
Matrix是矩阵。这里一不当心,就构建出了一个矩阵。表做为最经常使用的数据,是由于能够构建不少东西。
表的测量的两个函数是:Length、Dimensions
很好理解,前者返回表的长度,后者返回表的维数。
Length[{1, a, b}] (*返回3,很好理解*)
Dimensions[{1, a, b}] (*返回{3},很差理解*)
由于表啊,能够是一维,也能够是多维。在多维时,能够是规则的多维(好比矩阵),也能够是不规则的多维。因此使状况复杂了。
咱们来细看一下:
lis = {{{1, 2}, {3, 4}, {5, 6}}, {{a, b}, {c, d}, {e, f}}};
lis // TreeForm
lis // Length
lis // Dimensions
lis
Clear[lis];
lis =.;
lis
lis只是给输入的表起了个名字,能够理解为别名。用完了以后,最好取消别名。程序中给出了两种取消的方法。
给人家取了绰号,不能老叫啊。。老叫不礼貌。
取消了以后,lis就是一个符号,再也不是表的别名了。若是后面一不当心又用了lis,就不容易出错。
观察树形结构,若是根节点是第0层,那么Length返回的是第1层的元素个数,这里是2。
Dimensions 返回的是"规则"列表的维数列表,这里是:{2, 3, 2}
意思是树形结构中,第0层节点均有2个分支、第1层节点均有3个分支、第2层节点均有2个分支。
所谓“规则”列表的意思是,每一个节点上的分支数是要同样的。
那若是不同会咋样呢?
Dimensions[{{a, b, c}, {d, e}, {f}}]
得:{3}
根节点下,有3个分支,OK,得3。而后第1层节点下分支数不一样了,Dimensions就中止工做(输出),歇菜。
{{a, b, c}, {d, e}, {f}} // TreeForm
TreeForm很好用啊。。树形结构很好用。。
----------------------------------------------------
三、对表中元素的处理
处理?无非取得一些、添加一些、替换一些。还有一些是你想不到的,咱们一一来举例说明。
---------------------------
Position[{a,7,a,2,4,4},a]
得:{{1}, {3}}
列表中的元素位置,是从1开始的,不是从0开始。
为啥不返回:{{1,3}} ?
请看:
Position[{{1,f,3},{4,5,f}},f]
得:{{1, 2}, {2, 3}}。f在第1行的第2列,和在第2行的第3列。
{1,2}这种形式,已经有人用过了。。
还有一个要注意一下:列表函数的返回值,常常以列表形式出现。由于列表函数常常嵌套使用,表中有表。。
---------------------------
Part[{1,2,f,4},3]
{1,2,f,4}[[3]]
抽取表中的第3个元素,这两种方式抽取,结果是同样的。
也就是说[[]]只是表面,在MMA内部,仍是Part...还记得吧?MMA内部结构,都是函数(表达式)。
Part还有两个功能:
Part[{{1, f, 3}, {4, 5, f}}, 1, 2]
得:f
取得数组中的第1行、第2列元素。
在MMA中,数组常常指比较规则的表(用树形结构看,分支数相同),与C、Pascal中的数组概念不一样的。
这个程序看起来,有点不太明显,用下面的是同样效果:
{{1, f, 3}, {4, 5, f}}[[1, 2]]
这样看起来,要好理解不少。
Part[{{1, f, 3}, {4, 5, f}}, {1, 2}]
{{1, f, 3}, {4, 5, f}}[[{1, 2}]]
这两句是等效的,猜猜看,获得什么结果?
既然如此,来个更复杂的:
{{1, f, 3}, {4, 5, f}}[[{1, 2}]][[{1, 2}]][[{1, 2}]][[1,2]]
这就是传说中的语法糖。
用好了,代码可阅读性急剧提升。
用差了,代码就不知所云了,变成恶搞了(好比上面这个)。
---------------------------
Take,能够前取、后取、连续取
Take[{1,2,3},1]
Take[{1,2,3},-1]
Take[{1,2,3},{1,2}]
Take[{1,2,3},{-3,-1}]
Take[{1,2,3},{-3,2}]
Drop,能够前删、后删、连续删
Drop[{1,2,3},1]
Drop[{1,2,3},-1]
Drop[{1,2,3},{1,2}]
Drop[{1,2,3},{-3,-1}]
Drop[{1,2,3},{-3,2}]
---------------------------
Delete,删除指定位置上的元素。
Delete[{1, 2, 3, 4, 5}, {{2}, {3}}]
得:{1, 4, 5}
Delete[{{1, f, 3}, {4, 5, f}},{1, 2}]
得:{{1, 3}, {4, 5, f}}
Delete要删除的,都必须特别指定位置。若是想连续删,用Drop。
---------------------------
First/Last/Rest,不言自明:
First[{1,2,3}]
Last[{1,2,3}]
Rest[{1,2,3}]
注意两点:First和Last返回的不是表,是表中的元素。
而Rest返回的是表。
---------------------------
Select/Reverse/Sort,又是不言自明的。
Select根据特定条件抽取表中元素。特定条件就是谓词,返回布林值,即不是真就是假。
Reverse是反转表。
Sort是排序。
Select[{1,2,3,4},EvenQ]
Reverse[{1,2,3,4}]
Sort[{2,1,4,3}]
与EvenQ相似的有不少,能够顾名思义:IntegerQ OddQ TrueQ PrimeQ ...
Sort默认是排出升序。但也能够指定为降序:
Sort[{4, 1, 3, 2, 2}, Greater]
在Greater位置,也能够放上排序函数。
---------------------------
RotateLeft/RotateRight
这两个函数,能够把表当作是能够转动的轮子。
能够指定转动步长。
RotateLeft[{1,2,3,4},1]
RotateRight[{1,2,3,4},2]
---------------------------
Flatten
能够把嵌套表,展平(flatten,或者翻译成压平更容易理解?)到各类不一样的层次。
说到层次,又要用树形结构。
lis = {{{1, 2}, {3, 4}, {5, 6}}, {{a, b}, {c, d}, {e, f}}};
lis // TreeForm
Flatten[lis, 1]
% // TreeForm
Flatten[lis, 2]
% // TreeForm
lis =.;
观察输出结果,很容易理解。感性理解,就是一层一层剥皮,即把{}一层一层从外到内剥离。
那么不指定层次会如何?指定层次越大了会如何?能够玩一下:
lis = {{{1, 2}, {3, 4}, {5, 6}}, {{a, b}, {c, d}, {e, f}}};
lis // TreeForm
Flatten[lis]
% // TreeForm
Flatten[lis, 200]
% // TreeForm
lis =.;
答案揭晓:不指定层次,是一剥到底。层数过大时,也同样是一剥到底。
---------------------------
Partition
功能十分强大而复杂,这里只介绍经常使用的两个功能。
Partition[list,n]
将列表 list 分割成不重叠的具备长度 n 的子列表
Partition[Range[10],2]
Partition[list,n,d]
生成偏移量为 d 的子列表
Partition[Range[10],2,5]
---------------------------
Transpose
转置表中的前两层。
lis = {{a, b, c, d}, {1, 2, 3, 4}};
lis // Transpose
lis =.;
得:{{a, 1}, {b, 2}, {c, 3}, {d, 4}}
从表的角度看,是内部穿线同样。
从二维数组或者矩阵的角度看,如同行列转换:
lis = {{a, b, c, d}, {1, 2, 3, 4}};
lis // MatrixForm
Transpose[lis] // MatrixForm
lis // TableForm
Transpose[lis] // TableForm
lis =.;
---------------------------
Append/Prepend
添加元素到表的前面、后面。
Append[{1,2,3},4]
Prepend[{1,2,3},4]
---------------------------
Insert/ReplacePart
Insert[list,elem,n]
在 list 中的位置 n 上插入 elem。 若是 n 为负,位置从结尾计算。
Insert[{1, 2, 3}, a, 2]
Insert[{1, 2, 3}, b, -2]
能够观察到,当n为正数时,插入到指定位置前面。当n为负数时,插入到指定位置的后面。
ReplacePart[expr,i->new]
产生一个表达式,其中用 new 替换 expr 的第 i\[Null] 个元素.
ReplacePart[{1, 2, 3}, a, 2]
第2个位置的元素(2),被a替换掉了。
这是MMA较老版本(好比2.0版)的写法,如今也是支持的。较新版本(好比9.0版本)通常写成这样:
ReplacePart[{1, 2, 3}, 2 -> a]
效果是同样的。但新版本的写法能够扩充:
ReplacePart[{1, 2, 3}, {1 -> a, 3 -> c}]
这里第一次碰到转换符号:->,之后还会详细说的。
----------------------------------------------------
四、对多个表的处理
Join / Union
Join[{1,2},{3,4},{5,6}]
Join将数个表链接起来。另外,Join还能够指定层数链接,这里不举例了。
Union[{6,6},{3,4},{1,1}]
Union链接数个表以后,还把重复元素去掉,而后再排序。这有点集合操做的味道了,取并集。
由于Union有去重排序功能,固然也能够对一个表操做。但Union没有指定层数的功能。
Complement / Intersection
Complement求第一个列表中不出如今后面任何一个列表中的元素
Complement[{a, b, c, d, e}, {a, b, c}]
得:{d, e}
判断元素属于集合A、而不属于集合B。
(*
这里彷佛缺乏一个属于的判断函数。
可使用Position函数与Length函数来作属于函数。数组
——想多了,能够F1这两个函数:Element MemberQ
*)
MMA彷佛还缺乏一个取补集的函数。且慢,若是把Complement函数的两个参数,看做表1与表2,
而后呢,把表1看做是全集,把表2看做是子集,那么Complement返回的就是补集!
继续来看Intersection函数。
Intersection[{1, 2, 1, 3}, {2, 1, 4}, {4, 1, 2, 3}]
得:{1, 2}
求交集。由于相似于集合运算,因此有去重排序功能。
若是用语法糖,直接写成这样,会更清楚:
{1, 2, 1, 3} \[Intersection] {2, 1, 4} \[Intersection] {4, 1, 2, 3}
----------------------------------------------------
五、高阶函数
有一些内置函数,把其余函数做为本身的参数,咱们称之为:
高阶函数(higher order function)。
其实就是函数嵌套啦。
---------------------------
Map
这个函数能够将某一函数,做用于一个表的每一元素上。
Map[f, {3, 5}]
Map[Reverse, {{a, b}, {c, d}}]
Map[Sort, {{2, 6, 3}, {2, 4, 1}, {2, 3, 1, 4, 6}}]
MMA常常搞批发。这里显现出来了。
---------------------------
MapThread
多表元素,被分别组配到一块儿做为函数的参数。看例子:
MapThread[g, {{a, b, c}, {x, y, z}}]
MapThread[Power, {{2, 6, 3}, {5, 1, 2}}]
MapThread[List, {{5, 3, 2}, {6, 4, 9}}]
Transpose[ {{5, 3, 2}, {6, 4, 9}}]
最后两行的功能是同样的,Transpose的功能前面说过。
可是呢,Transpose只能有相似于行列转换的功能,而MapThread功能就强多了。
另外,MapThread还有指定层数的功能。
---------------------------
Outer
将把一个函数做用于几个表的元素的一切组合上。这是数学上外积(outer product)概念的通常化。
Outer[f, {a, b}, {2, 3, 4}]
Outer[List, {a, b}, {2, 3, 4}]
---------------------------
Apply
替换函数头。
Apply[f, List[1, 2]]
Apply[Plus, List[1, 2]]
---------------------------
这里多做点说明。
由于Map与Apply很是经常使用,因此有必要多了解一些。
Map[f, {3, 5}]
f /@ {3, 5}
Apply[f, List[1, 2]]
f @@ List[1, 2]
先后两句的功能是彻底同样的,
Map的语法糖是:
/@ 分别做用于
Apply的语法糖是:
@@ 仅替换函数头
---------------------------
Map与Apply,都可以指定层数。
Map[f,expr] 或 f/@expr
将 f 应用到 expr 中第一层的每一个元素.
lis = {{{1, 2}, {3, 4}, {5, 6}}, {{a, b}, {c, d}, {e, f}}};
lis // TreeForm
Map[f, lis] (*做用于第1层*)
Map[f, lis, {2}] (*做用于第2层*)
Map[f, lis, 2] (*做用于第一、2层*)
lis =.;
Apply[f,expr]
或 f@@expr 用 f 替换 expr 的头部.
lis = {{{1, 2}, {3, 4}, {5, 6}}, {{a, b}, {c, d}, {e, f}}};
lis // TreeForm
Apply[f, lis] (*做用于第0层*)
Apply[f, lis, {2}] (*做用于第2层*)
Apply[f, lis, 2] (*做用于第一、2层*)
lis =.;
---------------------------
附加说明函数的属性。
MapThread[Plus,{{1,2,3},{1,2,3}}]
得:{2, 4, 6}
直接写:
{1, 2, 3} + {1, 2, 3}
结果同样。
既能够被自动地转到表参数的各个元素上,又能够被自动地穿线于表参数的对应元素上的那些函数,咱们称之为具备可做用于表的元素的(Listable)属性,即具备Listable属性。许多MMA内置函数都具备这一属性。
查看函数的属性,用Attributes函数:
Attributes[Log]
Log[{2, 3, 4}, {4, 9, 16}]
由于Log函数有Listable属性,因此有这种“穿线”功能。
---------------------------
Attributes[Plus]
得:{Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected}
Flat, 可结合的,即服从结合律。
Listable, 前面已经说明,有“穿线”功能。
NumericFunction, 顾名思义,用于数值计算的函数。
OneIdentity, 函数对同一参数的重复做用是无效的,Plus[Plus[a + b]] // FullForm
Orderless, 无顺序的,即服从交换律。a+b与b+a同样的。
Protected, 受保护的。用户被禁止以任何显著的方法来修改这个符号。有点其余语言中保留字的味道。
----------------------------------------------------
六、函数对表的重复做用
这些函数,对作迭代很是方便。
---------------------------
Nest / NestList
Nest[f, x, 5]
得:f[f[f[f[f[x]]]]]
函数做用于参数,返回值做为参数,再被函数。。做用了5次。
NestList[f, x, 5]
得:{x, f[x], f[f[x]], f[f[f[x]]], f[f[f[f[x]]]], f[f[f[f[f[x]]]]]}
整个做用过程,给出了表。这样全过程就很清楚了。
ff[x_] := x + 1;
NestList[ff, 0, 20]
---------------------------
Fold / FoldList
在每一次迭代中,即函数返回值做为参数时,还另加表中的一个元素做为第二个参数。
Fold[f, 0, {a, b, c, d}]
得:f[f[f[f[0, a], b], c], d]
FoldList[f, 0, {a, b, c, d}]
将整个过程当中,每一个步骤所得,均取出来,做为表元素。
FoldList[Plus, 0, {a, b, c, d}]
FoldList[Plus, 0, {3, 5, 2, 4}]
FoldList[Plus, 0, Range[100]]
这个迭代过程很低效,只是为了说明Fold的迭代过程。1+2+3+...+100,最后得5050
---------------------------
Inner
被当作是数学中点乘运算(Dot函数)的推广。
Dot (.)
a.b.c 或 Dot[a,b,c]
给出向量、矩阵和张量的乘积,即点乘运算。
{a, b, c} . {x, y, z}
Inner[f, {a, b, c}, {d, e, f}, g]
得:g[f[a, d], f[b, e], f[c, f]]
f起到“穿线”组合参数的功能。而g起到最后的结合功能。
Inner[Times, {a, b, c}, {d, e, f}, Plus]
得:a d + b e + c f
Inner[List, {a, b, c}, {d, e, f}, Plus]
先是List起做用,产生三组表。而后是Plus起做用,用了“穿线”加法,最后得:
{a + b + c, d + e + f}
----------------------------------------------------
七、字符串和字符
字符串,在MMA中,是atom,最基本的数据类型。相似于一个值,不,就是一个值。
咱们说,在MMA中,一切都是表达式。除了函数,就是atom。
字符串不是函数、更不是字符数组,是atom。
1 // FullForm
"test" // FullForm
"test" // InputForm
Length["mathematica"]
---------------------------
StringLength...
字符串很特殊啊、不是这个不是那个,更不是表。因此表操做函数,不能直接用于字符串。
坏消息啊。
不过,好消息是:通常的表操做函数,前面加上String,就能够用了:
StringLength["Mathematica"]
StringReverse["abcdefg"]
StringTake["abcde", 3]
StringDrop["ABCDE", -1]
StringPosition["abcde", "bc"]
...
能够看到,从原理上,把字符串做为字符列表来处理了。。
从学习上来讲,咱们没必要从头至尾再学习一遍串操做函数了,由于与表操做函数太像了。。
一眨眼间,大部分串操做函数就理解了。
接下来,来几个针对串操做的固定有函数。
---------------------------
ToCharacterCode/ FromCharacterCode
ToCharacterCode["mathematica"]
% - 32
FromCharacterCode[%]
第一句,转化字符为ASC码。
第二句,上句输出表中每一个元素减去32。
第三句,上句输出表中每一个元素,转化为字符。
能够看到,小写都变成大写了。
由于字符与ASC码之间,能够轻松转化,那字符操做,就没有问题了。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
秘密就在于:
由于MMA中任何事物,都具备表达式这一共同结构,因此在表操做中学到的大部份内置函数,也能够用来对任何表达式(atom除外)操做。
清楚了吧?不少表操做函数,不是表专用的,其余表达式上均可以用。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
虽然这章有点长,但咱们能够说,最经常使用的MMA函数,咱们都掌握了。
MMA学习曲线上的重头戏,就这么愉快地上演完毕。
数据结构
++++++++++++++++++++++++++++++++less
扩展阅读:木有。若是有时间,把经常使用表操做函数拼写几遍,熟练一下函数功能。函数
这里有个mathematica 经常使用命令大全,按函数功能进行划分,有时候能够查阅。学习
Top
atom