2、表操做


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

相关文章
相关标签/搜索