说明
最近心里总是很烦,不知道为什么,可能大学要毕业了,对未来还是很迷茫,不知道怎么办,很难受。希望以后能好起来吧。
1.3 自带模式的内置函数
1.3.1 Cases
这个函数通常用在表达式的结构上。
更准确地说,它用于表达式中与特定模式匹配的子表达式。
下面举例子说明
Example:从列表中选择整数
Clear[testlist]
testlsit={1,2,3,1.3,Pi}
Cases[testlist,_Integer]
需要注意的是我们在这里,不需要给模式命名,以为我们不需要对结果就行任何操作。
Example:根据条件去掉一些数字
我们来考虑这么一个特殊的例子:假设我们有一组数据,我们需要去掉那些比0.3小的数字
Clear[eps, data];
eps = 0.3;
data = Table[Random[], {10}];
Cases[data, x_ /; x > eps]
{0.861627, 0.807515, 0.627041, 0.519299, 0.831482, 0.789996, 0.90291,
0.420605, 0.694002}
拓展功能
Cases
还有一个功能是立即对找到的结果执行一些转换。
语法是Cases[expr,rule,levespec,n],和前面一样后面的两个参数是可以选择的,我们可以看到我们现在的模式是一个规则,模式是它的l.h.s (左边)。
比如说,现在我们想找到一个除以5余0的数字,如果余数是0就返回True,如果是不是就返回False.
data1 = Table[RandomInteger[{1, 100}], {10}]
Cases[data1, x_ :> {x, Mod[x, 5] == 0}]
{87, 22, 15, 5, 85, 71, 11, 53, 78, 59}
{{87, False}, {22, False}, {15, True}, {5, True}, {85, True}, {71,
False}, {11, False}, {53, False}, {78, False}, {59, False}}
在一个列表中选择正数
首先我们造一个列表
Clear[list];
list = Table[RandomInteger[{-10, 10}], {15}]
{-7, 5, 5, 4, -3, -3, 9, 4, 7, 10, 10, 7, 2, -6, 3}
然后用模式匹配一下就行了
Cases[list, _?Positive]
{5, 5, 4, 9, 4, 7, 10, 10, 7, 2, 3}
Example:嵌套列表的匹配
我们来考虑一个二维列表
Clear[list];
list=Table[i+j,{i,1,4},{j,1,3}]
{{2, 3, 4}, {3, 4, 5}, {4, 5, 6}, {5, 6, 7}}
假如现在我们想把所有的偶数都选择出来。
我们来试试看
Cases[list,x_EvenQ]
{}
很遗憾,结果不是我们想要的。
为什么会这样呢,因为Cases函数默认情况下是作用在第一层列表上,我们这里的第一层列表不是数字,我们列表的第二层才是数字。这里我们可以用FullForm看看看。
list//FullForm
List[List[2,3,4],List[3,4,5],List[4,5,6],List[5,6,7]]
所以我们应该这么做:
Cases[list,x_?EvenQ,2]
{2, 4, 4, 4, 6, 6}
这里参数2的意思是从第1层到第二层的所有偶数,我们也可以把这个限制在第二层,用 {2}
Cases[list,x_?EvenQ,{2}]
{2, 4, 4, 4, 6, 6}
在这种情况下,2和{2} 并没有说明区别,但是如果现在我们想要找到的不是数字而是子列表。我们可以这样做:
Clear[found];
Cases[list,x_List:>Total[x]]
{9, 12, 15, 18}
上面这个就是我们作用在子列表。
我们还可以对子列表施加一些条件,例如,只找到那些包含数字4的子列表:
Cases[list,x_List/;Cases[x,4]=!={}]
{{2, 3, 4}, {3, 4, 5}, {4, 5, 6}}
如果说我们想搜索第二层
Cases[list, _list, {2}]
{}
返回的是空值,因为第二层都是数字,没有列表。
Example: 解决奇数子列表的简单解决方法
重新说明一下这个问题:
我们想要找到包含 奇数个奇数的子列表。我们曾经用很复杂的办法解决这问题的,现在我们用Cases快速解决他。
这里是我们的列表:
Clear[list];
list=Range/@Range@6
{{1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4,
5, 6}}
Example:列表中第一个质数
假设我们想要得到一组数字中的第一个给定的质数。
list=Table[Random[Integer,{1,100}],{30}]
{8, 68, 62, 58, 91, 44, 34, 17, 27, 60, 45, 59, 85, 99, 7, 49, 28, 4,
33, 42, 45, 100, 8, 6, 18, 11, 89, 49, 48, 88}
比如说我们想要挑出前3个质数
Cases[list, _?PrimeQ, 1, 3]
{17, 59, 7}
请注意,在这里我们仍然需要提供第三个参数(level specification),尽管对于简单列表来说这通常是不需要的(默认为1)
这是因为,否则3的参数将被解释为一个层数,如果我们不加1这个参数,我们将得到所有的素数。你可以试一下
为什么不使用循环?
你可能认为在上面给出的所有例子中使用循环会产生相同的结果。
我们为什么不使用循环呢?
就一句话:效率低下!我多次说明mathematica中不要使用循环,不要使用循环!
Example 在一个有两个变量的多项式中挑选某些需要的项
我们要在(1+x)^10*(1+y)^10中挑选那些x的幂为奇数,y的幂为偶数的项。
Clear[a,x,y];
Cases[Expand[(1+x)^10*(1+y)^10],a_*x^_?OddQ *y^_?EvenQ,Infinity]
{5400 x^3 y^2, 11340 x^5 y^2, 5400 x^7 y^2, 450 x^9 y^2,
25200 x^3 y^4, 52920 x^5 y^4, 25200 x^7 y^4, 2100 x^9 y^4,
25200 x^3 y^6, 52920 x^5 y^6, 25200 x^7 y^6, 2100 x^9 y^6,
5400 x^3 y^8, 11340 x^5 y^8, 5400 x^7 y^8, 450 x^9 y^8, 120 x^3 y^10,
252 x^5 y^10, 120 x^7 y^10, 10 x^9 y^10}
最后一个参数设置为无穷大意味着应该搜索表达式的所有层数,也就是把符合条件的所有层都找出来。
1.3.2 DelectCases
从这个函数的名称可以清楚地看出,它从一个列表中删除了与给定模式匹配的所有元素。它的语法类似于case。
和Cases的区别是,Cases返回一个已找到的子表达式列表,而DeleteCases返回原始列表的(副本),这些子表达式已被删除。
Example :删除列表中的偶数
Clear[list];
list=Range@15;
DeleteCases[Range@15,_?OddQ]
{2, 4, 6, 8, 10, 12, 14}
我们刚把所有奇数从列表中删除了。但list这个列表本身没有发生任何变化。
我们可以看看。
list
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
在这方面,DelectCases操作与大多数Mathematica内建命令的工作方式相同,而且没有副作用:创建和修改输入变量的副本。
如果我们想要更改list的内容,你可以这样:
list = DeleteCases[list, _?OddQ]
{2, 4, 6, 8, 10, 12, 14}
然后你在输入list,运行就会改变list的内容了。
让我们执行一个时间测量:测量删除从前100000个自然数中删除那些余数除以5小于2的自然数所需要的时间:
Timing[Short[DeleteCases[Range@100000, x _ /; Mod[x, 5] <= 2]]]
{0.015625,{1,2,<<99996>>,99999,100000}}
看到没有速度特别快。然我们再来看看垃圾循环。
Module[{i, j, result, s},
For[i = j = 1; s = result = Range@100000, i <= 100000, i++,
If[Mod[s[[i]], 5] <= 2, result[[j++]] = s[[i]]]];
Take[result, j - 1]] // Short // AbsoluteTiming
{0.56624,{1,2,<<59996>>,99997,100000}}
很明显使用循环比Cases慢了几百倍!所以别用循环了!
Example :非零的整数子序列
考虑以下问题:我们得到一个整数列表,其中一些可以是零,我们要做的是从列表中提取连续的非零元素的所有子序列。
Clear[list]; list = Table[Random[Integer, {0, 3}], {20}]
{2, 2, 1, 1, 0, 0, 2, 1, 3, 2, 0, 2, 2, 2, 2, 0, 0, 2, 0, 2}
解决这个问题的第一步是使用Split,在遇到零时将元素拆分为子列表.
step1 = Split[list, #1 != 0 &]
{{2, 2, 1, 1, 0}, {0}, {2, 1, 3, 2, 0}, {2, 2, 2, 2, 0}, {0}, {2, 0}, {2}}
不过,我们在子列表中得到了一些0,因此必须删除它们。
step2 = DeleteCases[step1, 0, {2}]
{{2, 2, 1, 1}, {}, {2, 1, 3, 2}, {2, 2, 2, 2}, {}, {2}, {2}}
最后,前面的操作通常会从包含一个0的子列表生成一些空列表,我们现在也必须删除它们:
step3 = DeleteCases[step2, {}]
{{2, 2, 1, 1}, {2, 1, 3, 2}, {2, 2, 2, 2}, {2}, {2}}
现在我们打包起来:
Clear[f];
f[x : {__Integer}] :=
DeleteCases[DeleteCases[Split[x, #1 != 0 &], 0, {2}], {}]
f[list]
{{2, 2, 1, 1}, {2, 1, 3, 2}, {2, 2, 2, 2}, {2}, {2}}