函数是 Power Query (PQ) 解决问题的核心。之前的博客文章我多层刻意在完成查询的步骤之后显示高级编辑器中 M 语言代码,想必大家已经对 M 的函数有了初步印象,尽管不一定很关注。本篇介绍 M 函数比较重要的知识点。

要点:

  • 理解 M 语言的函数式编程风格
  • 函数的定义和调用
  • 函数作为函数参数传递
  • 自定义函数基础

学习 PQ 的处理数据,尽管我们大部分是在查询编辑器图形化界面中操作,但幕后将我们操作步骤记录下来的,都是 M 语言的代码。M 语言的代码,主要由函数构成。M 语言的函数与 Excel 函数不同,与其他常规编程语言的函数也不同,属于典型的函数式编程风格。为了更好的掌握 M 代码的编写,建议用自己熟悉的编程语言 (比如 Python)多去了解函数式编程的特点。

我们先解释一下 M 函数的基本语法格式。M 函数采用的是一种 F# 类似的语法。举一个例子,假如我们要编一个函数,实现两个数字相加,这个技术上都没有任何难度,示例主要目的就是为了熟悉 M 语言函数的语法。

函数的定义

进入查询编辑器,新建一个空查询,将查询名改为 add,进入高级编辑器,在高级编辑器中输入下面的一行代码:

(x, y) => x + y

这就是 M 语言的函数,箭头符号 (=>)左边是参数列表,箭头符号右边是函数体。点击完成按钮回到查询编辑器,此时界面如下:


有几个值得我们注意的地方。第一:左边查询列表中 add 的符号变成 fx,表示这是一个函数,与之前介绍的查询概念不同。PQ 的函数可以供其他查询或者函数调用,得到一个返回值,从而对功能进行一个封装,增加代码的灵活性。

第二:这种独立编写的函数(top level function)在当前工作簿中,可以被其他查询或者函数调用

第三:PQ 提供了图形化界面,可以在界面中输入参数值进行测试。标准库的函数也可以用这种方式来运行和测试结果。


点击调用按钮,PQ 自动创建一个新的名为“调用的函数”的查询,查询编辑器的界面显示了调用的结果:

参数的数据类型

选中 add 函数,再次进入高级编辑器,将代码修改为:

(x as number, y as number)  as number => (x + y)

点击完成按钮回到查询编辑器界面,比较一下与之前界面的区别:


用这种方式,限定了参数和函数返回值的类型。

函数也可以与 let 语句一起使用,比如这个简单的 add 函数,将代码修改为如下:

let result = (x, y) => (x + y)
in result

代码的功能与前面相同。这段代码可以理解为:定义一个两数字相加的函数,将函数赋值给 result,result 作为结果输出到函数 add。

如果函数比较简单,又是临时用一下,编写一个 top level function 就显得比较浪费,这种情况下,可以在查询步骤中定义函数。为了区分,可以将嵌入在查询步骤中的函数称为内联函数 (inline function)。

所以记住 M 语言可以在两个位置定义函数:

  • top level function
  • inline function

新建一个空查询,在高级编辑器中编写如下代码:

let add = (x, y) => (x + y),a = 10,b = 20,result = add(a, b)
in result

这段代码定义了一个名为 add 的函数,并且调用函数对 a 和 b 两个变量相加,计算的结果通过 result 进行输出。

函数的调用

Power Query 标准库中一共有 700 多个函数,有些函数非常简单,有些则非常复杂。我们先看一个简单的函数:

Text.Proper(text as nullable text, optional culture as nullable text) as nullable text

依据 Microsoft Docs: Text.Proper:

Returns the result of capitalizing only the first letter of each word in text value text. All other letters are returned in lowercase.

将文本的首字母变成大写,其他字母全部小写。我们直接在查询编辑器中调用该函数:

这是简单函数的调用,看不出与其他语言的函数有什么区别,对吧?演示一个稍微复杂一点的函数 List.Select,我们先看看 Microsoft Docs - List.Select 的语法和解释:

List.Select(list as list, selection as function) as list

根据筛选条件,返回 list 中匹配的元素作为一个新的 list,筛选条件必须是一个函数。

函数能作为参数进行传递,是函数式编程的一大特点。考虑到 Power Query 主要面向数据处理人员,这里不对函数式编程进行展开说明,但需要了解这一特点。函数作为参数的函数,如何调用呢?我们先给出调用示例,在高级编辑器中输入下面的代码:

//  输出 1 到 30 所有能被 3 整除的整数
let    source = {1..30},result = List.Select(source, (x) => Number.Mod(x, 3) = 0)inresult


对代码解释一下: List.Select 函数规定第二个参数是一个函数,用于表示筛选条件。

(x) => Number.Mod(x, 3) = 0

这个函数定义了一个筛选条件,当 x 能被 3 整除,则返回 true,为了表示能被 3 整除这个条件,函数又调用了另外一个 Number.Mod 函数,用于判断是否能整除。

当代码中调用 List.Select 函数的时候,List.Select 函数 自动遍历 list 中的每一个元素,并且将元素赋值给函数第二个参数(即函数 (x) => Number.Mod(x, 3) = 0 )中的参数 x,然后调用这个匿名函数,当返回 true 时,这个元素就被判定为匹配,加入到返回值的 list 中。因为 List.Select 具有自动遍历的功能,所以我们也可以理解为,List.Select 的第二个参数必须是函数,这个函数含有一个名字不重要的变量 (x),对这个变量 (x) 运行一个函数后,能计算得到 true 或者 false。对刚才的查询稍微改一下,以加深大家的理解:

// Get numbers greate than 20
let    source = {1..30},result = List.Select(source, (current) => current >= 20 )inresult

Power Query 的 each 究竟是什么

前面我们在 PQ 中处理数据的时候,经常看到有 each,因为没有介绍函数,也就一直没有解释。这个 each 究竟是什么呢?each 定义了一个接收唯一参数的函数,是对 (_) => expression 的简写。下划线 (_)在 M 语言中,代表函数无类型唯一的参数。根据这一解释,上面的代码可以简化为:

let    source = {1..30},result = List.Select(source, (_) => _ >= 20 )  // parameter name inresult

或者:

let    source = {1..30},result = List.Select(source,  each _ >= 20 )inresult

函数是 Power Query 的核心,也是难点。为降低学习难度,先介绍这些基础,后续再逐步深化。

References

  • Power Query M function reference

Power Query 系列 (11) - 函数基础相关推荐

  1. Power Query 系列 (13) - 自定义函数

    本篇博客介绍 Power Query 自定义函数的技巧,在 PQ 中计算个税. 以工资类所得应交个税为例,最新的个税起征点为 5000 并按下表的级次进行缴税(假设没有其它扣除项). 对照税率表,我们 ...

  2. BI神器Power Query(11)-- PQ M函数快速查询

    Power Query M 函数超过700个,基本上不太可能完全记住全部的函数的使用方法,大家可以通过微软在线帮助(Power Query M 函数参考)查询函数的含义和使用方法. 其实在Power ...

  3. Power Query 系列 (12) - Power Query 结构化列应用案例

    本篇数据处理来自一个实际处理数据的简化.下图中,假设左边是一个直观的 BOM 结构展示,数据在 Excel 中存储格式如中间部分所示:第一列为物料编码的级别,第二列为物料编码.数据处理任务:需要在 E ...

  4. Power Query 系列 (01) - Power Query 介绍

    Power Query 介绍 Power Query 是微软提供的工具,Excel 2013 版作为插件加载使用,从 Office 2016 版开始,Power Query 的功能集成到 Excel ...

  5. Power Query|M函数:数据类型及数据结构

    转载自微信 前言: 查询增强版(Power Query)是Excel Power BI组件中用于数据导入.数据整合以及数据处理的插件工具.适用于Excel 2010以上版本,在Excel 2010以及 ...

  6. powerquery分组_Power Query系列 - 排序Ranking

    Power Query系列 - 排序Ranking 难度: ★★☆☆☆(1星) 适用范围: ★★★☆☆(3星) 概况: 在数据分析中,我们常常需要对数据进行排序,同时我们想知道某个项目或者产品的排名, ...

  7. SQL Server 2008空间数据应用系列四:基础空间对象与函数应用

    SQL Server 2008空间数据应用系列四:基础空间对象与函数应用 原文:SQL Server 2008空间数据应用系列四:基础空间对象与函数应用 友情提示,您阅读本篇博文的先决条件如下: 1. ...

  8. Power Query M函数_我常用的玩法

    跟据日期字段,为表格增加年. 月.日3个字段 = Table.FromRows(List.Transform(Table.ToRows(ZCESRSET_Table),each _ & [a= ...

  9. power query 向下填充_Power Query 系列 (12) - Power Query 结构化列应用案例

    本篇数据处理来自一个实际处理数据的简化.下图中,假设左边是一个直观的 BOM 结构展示,数据在 Excel 中存储格式如中间部分所示:第一列为物料编码的级别,第二列为物料编码.数据处理任务:需要在 E ...

最新文章

  1. Intel qsv + ffmpeg 硬解h264
  2. COSCon'21 参会指南 你想要的这里都有
  3. 上海理工大学第二届“联想杯”全国程序设计邀请赛 Identical Day 思维 + 暴力
  4. topcoder srm 410 div1
  5. 编织让你受益一生的交际网
  6. 小记css的margin collapsing
  7. java用下划线分开字母和数字_数字文字中的Java 7下划线
  8. 计算机桌面图标出现蓝框,计算机桌面图标出现蓝框?
  9. Siebel应用数据结构层次
  10. Python 标准库之 random 生成伪随机数『详细』
  11. 华三H3C交换机如何配置堆叠irf虚拟化之如何配置检测机制(配置BFD MAD检测)
  12. 阿里云Epel镜像的安装方法
  13. 用C轻松实现扫雷,简单,普通,困难模式快来学学吧
  14. videos player.php_vue-video-player做出一个自定义播放器
  15. ubuntu安装ssh并开机启动
  16. 从身份证图片获取文字信息
  17. php pinterest,使用PHP解析pinterest JSON api
  18. 打折策略模式java_策略模式(java)
  19. matlab鱼群仿真程序,人工鱼群算法的仿真程序-matlab
  20. 86盒IP对讲一键报警器

热门文章

  1. 宇视录像机通道名称如何修改
  2. 一文读懂交叉熵和最大似然的关系及在人脸识别中的应用
  3. 多文档程序 两个menu框架_汇总9款优秀的开源小程序UI框架
  4. 解决视频文件播放不能快进问题
  5. 理财入门:财务报表(简单介绍,后续入门系列文章写完后,会写实践文章在详细介绍)
  6. linux虚拟光驱挂载教程,VMWare 挂载虚拟光驱及制作floppy linux
  7. UG NX 12 同步建模技术
  8. 三国志战略版:SP吕蒙携手都督重出江湖
  9. 使用谷歌、360浏览器的F12功能模拟微信访问网页
  10. crt不能回退_CRT优化与QRS波宽度的研究进展