找不到用户定义的文本运算符_Power Query — 运算符,注释

26ee1c47265a09367b70f205f06883f3.png

题记:

学术地学,业务地用。

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

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


运算符:

069f2964a24f24f303e1e4af0dc3a05e.png

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

1.四则运算:

3b37c2047b42593eda3ce1f16bb7f3f0.png

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

2.数学运算:

1f53184c1eab89d55c21ae9cb2210ec6.png

53996ff9cb1c02c6b983ed95301bcf44.png

122724275037f9a605be266f1aee31e7.png

9a96b1f7b6707b17e43d035130e67f30.png

37995864b98e3e7275c68df32db60a4c.png

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

fc65d6ad9323682dc5794017daed645a.png

11e2b8f2ec291ee0fd5d13494ba1272d.png

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

568258da7f7a9e5c4850debfbc08764d.png

特殊运算符:

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

1. [[X]] :

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

89ec75f1204f3973028201067eee8cb7.png

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

2. @ :

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

611022b9e9aaf7434f5c386597733598.png

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

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

8912c87d0bf38ad1dc1bb1185d66266d.png

f9242c0b2e95c6795c7fda112d77f122.png

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

cf4e7338a0d1f2a646a261306128891a.png

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

3. & :

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

24f32cb5dc50d3c96977e9dcfffa5079.png

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

4. !:

f1f92658c539bf0f6650a0e7b530be53.png

45ca99aedbbd22a49dcd297e4af042b6.png

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

f92aaaad70ace541d7b554a0fa7a9ea8.png

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

section Section1;

A = “Hello”;

B = 1 + Section2!A; //3

section Section2;

A = 2;

B = Section1!A & “ world!”; //”Hello, world”

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

333f8822e55082803110e66905381358.png

但是读者应该能够看得懂,这里的“!”起到了调用sections中参数的作用。

有兴趣的读者可以前往这个链接看section的具体用法:

Microsoft/DataConnectors​github.com
474cc21f387247735348d899eb9dbcdf.png

5. # :

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

b266b9d1c5869fb73d87d7c022f634b7.png

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

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

e046d5e16c8d6bdd6de97817acb5ca85.png

6. '" :

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

b5d6ad95bc417ee1d7968f7db7fae0a4.png

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

1c6c2ef4eef64f7c5fe6c15a4f8be47e.png

64a14093f2639a9f1cbdc2480655b4b2.png

290fea4a8d5ac1d0f421f11d915962e1.png

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

根据这个公式我们来算一下,输出9个"要输入多少个"?

输入=9*2+2=20;

f19f673330f09fa3cecb217e88ac9613.png

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

2a0945d98578626efec3eb5ca9774615.png

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

7. _ :

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

b08f223216c5fdaa53a6975a1e374463.png

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

987b0c060ea19edbc5cce951c70a6a46.png

59f4e8135d1727558a9d35d5fb36e505.png

8. ... :

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

ac6a8f7a8c7a67508bc3712635aead0e.png

6be08b774edb3a4b681e3de26b581c01.png

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

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

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


运算顺序:

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

841d3424f71926254b14429fb67880b7.png

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

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


注释:

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

c44fd3d549668eb7ac3625f9375f6b57.png

165c7e3a2383ce3f90d048f3a742291a.png

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

3f41243d5eb66b9ba71838e3a563fe52.png

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

简单总结一下:

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


下篇笔记:《函数初步