Mathematica——模式规则3


说明

最近心里总是很烦,不知道为什么,可能大学要毕业了,对未来还是很迷茫,不知道怎么办,很难受。希望以后能好起来吧。

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}}

文章作者: 我心永恆
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 我心永恆 !
评论
 上一篇
猫盘nas的一些事(1) 猫盘nas的一些事(1)
其实在一个月前我就想搞一个nas,只是因为毕业论文和其他的一些事情的原因,没什么时间折腾,这段时间还算可以,于是咸鱼入手了一个猫盘搞nas,在网上也是参考了不少资料,最后决定入手这个搭建自己的私人网盘。 这个是我入手的猫盘,下面是他的盒
2021-05-31 我心永恆
下一篇 
Mathematica使用MaTex包展现Latex效果 Mathematica使用MaTex包展现Latex效果
Mathematica使用MaTex包展现Latex效果一,准备工作准备以下东西 1.texlive软件包 下载链接:texlive 提取码:wxyh ​如果链接失效那么就用这个:备用texlive 2.mathematica软
2021-05-31 我心永恆
  目录