Power Query — 运算符,注释

不少人问我这有什么用啊,那个有什么用啊……

其实这类问题都不太好回答。它和“买菜用不到微积分,学高数有什么用?”这类问题挺像的,答案大家都知道。我觉得既然微软官方给已经很完善的Excel添加了这么一套BI插件,要么是用户有这个需求,要么是微软觉得这是符合未来需求的产品,而且这个产品确实丰富了Excel的功能,也确实能够在一些地方用得上,那么沉下心来学一学并没有太大的问题,至于不知道有什么用的话,就当开发自己的大脑吧~

运算符:

图01

上图摘至官方的语法手册,基本囊括了平时能够用到的全部运算符,我们来一起过一遍这些运算符,看看到底有什么作用!

1、四则运算:

图02

和很多编程语言一样,加法减法符合我们的一般认知,但是除法的结果可能和我们想象的不太一样,例如上述例子的四则运算中3*4/5=2.4000000000000004(当数字3参与一些运算时,结果与我们笔算的出入会大一些)。

2、数学运算:

图03
图04
图05
图06
图07

可见,M并不支持常规的^log/ln/e等这些写法,那么是不是意味着M不能够进行这些运算了呢?显然不是的。在M中有一个专门的函数类Number,可以方便地进行各种常规运算,也有专门的符号,用来表示e或者π这样的特殊数,如下图所示:

图08
图09

3、三角函数/反三角函数/双曲函数:

图10

特殊运算符:

有一些运算符你可能特别眼熟它,但是会用错它,有些运算符你可能经常看到,但是却完全不理解它的意思,这类运算符我姑且把它们称作“特殊运算符”吧。

1、[[X]] :

我们知道[x=1][x]是提取字段名为x的键所对应的值1,那么[x=1][[x]]呢?

图11

可见,[[x]]是完整地提取出字段x的键-值对。

2、@ :

一般我们会在邮箱中经常用到这个符号“@”,那么在M中呢?

图12

虽然这里去掉“@”的结果是一样的,但是这里表达的理念不一样,“@”实际上是起到了引用的作用,也就是b=@x的下一步是去找x是什么,然后将x的完整含义整体赋值给b。

下面这两个例子就能够很好地展现出去掉“@”前后的具体区别(引用/赋值):

图13
图14

当赋值表达式后的“@”接的自身时,M会报错:循环引用。

图15

而当赋值表达式后直接接自身时,因为自身还没被定义,M会报错无法识别。

3、& :

想必很多人一看就明白这个运算符的含义,但是涉及具体运算时,结果可能会和你想象的不太一样,例如下面的例子:

图16

是不是有点像并集运算?records和lists间的“&”运算可以自己尝试一下。

4、!:

图17
图18

可见M中的“!”并不能用作阶乘(上面已经讲解了怎么算阶乘)符号,也不能用来表示“非”,“!=”表示不等于的意思在M里面被“<>”替代:

图19

那么感叹号有用吗?答案是:有!

ection Section1;
A = "Hello";
B = 1 + Section2!A; //3

section Section2;
A = 2;
B = Section1!A & "world!"; //"Hello, world"

(section需要在VS里面使用,编辑器里面无法使用)

图20

但是读者应该能够看得懂,这里的“!”起到了调用sections中参数的作用。有兴趣的读者可以前往这个链接看section的具体用法:

参考:https://github.com/Microsoft/DataConnectors

5、#:

井号虽说也算不上一个运算符吧,但是还挺有用的,前面讲过生成一个table会用到#table,类似的还有:#binary、#date、#datetime、#datetimezone、#duration、#infinity、#nan、#sections、#shared、#time。这里面重点说一下#shared:

图21

我们可以通过输入“=#shared”快速地获取全部的M函数。

前面讲标识符的时候也说过#的一种用法,用来构造标识符:

图22

6、'" :

关于引号只讲一点——当你要输出引号的时候,你该如何输入?

图23

我们输入两个''才输出一个',而且还和编辑器自动生成的代码有出入,这是为什么?

图24
图25
图26

通过上述例子我们不难发现:输入的"个数=你要输出的"个数*2+2

根据这个公式我们来算一下,如果希望输出9个引号需要输入多少次"呢?答案是9*2+2=20次;

图27

这里留一道思考题给读者,如果将in后面的20个"改为“源”,结果是多少个"呢?

图28

(提示:函数的功能是生成一个有20个"的list然后将内部元素全部用&连接起来后输出)

7、_ :

下划线也是M里面常见的一种符号,一般搭配关键字each使用,指代“每一个”元素的意思:

图29

再看看下面两个例子(唯一区别是“x”换成了“_”)的对比,就更加清楚“_”的作用了:

图30
图31

8、… :

前面讲解list的时候介绍了“..”的作用,类似书写上“~”的作用,1~3就是{1..3},那么三个点呢?下面我们结合if表达式来看看效果:

图32
图33

这两个例子对比可以发现,未使用“…”的整个if表达式都是无法通过的,因为不完整(没有else),但是使用了“…”的表达式能够运行,但是会报error。

“…”的意思是不执行,因为没有执行任何语句,所以error称没有给a指定值。

实际应用当中,我们可能有时候只需要对if的一种情况做运算,其它情况不做运算,那么“…”就可以派上用场了。

运算顺序:

M里面运算是有顺序的,但是不是特别严格,这句话怎么讲呢?

图34

如果说M对过程的要求是严格的,那么上述表达式应该会报错,因为第一行a=b+1里面的b还没有定义,但是实际情况是可以顺利运行成功,并且结果是正确的。

说明M允许一定程度上的先引用-后定义,但是这并不意味着所有的M语句可以任意地交换顺序。假如你用的操作,那么操作步骤顺序基本上是不可交换的。

注释:

很多语句的可读性其实并没有想象当中的那么好理解,特别是用了一些特别巧妙的算法的时候,这时候我们就需要给语句写批注,既方便自己修改和阅读,也方便他人理解和维护。

图35
图36

通过上图对比发现,“//”确实把第一次对x和y赋值的表达式给注释掉了,编辑器没有报错。

图37

上图显示,通过“/* */”把两次给x和y赋值的表达式全部注释掉了,编辑器无法识别变量名了。

简单总结一下:

M里面可以使用“//”和“/* */”两种注释方式,其中单行注释使用“//”,跨行注释使用“/* */”。(养成良好的习惯从写注释开始!)

作者: Hugh

Welcome to Wan's world~