![5e7fb7ccb36d05ccd317a8b0ee9aa532.png](https://img-blog.csdnimg.cn/img_convert/5e7fb7ccb36d05ccd317a8b0ee9aa532.png)
2018-04-13学习笔记:
捋一捋Power Query里面的循环,迭代和递归
循环
在Power Query中循环是Transform类函数,如列表循环:List.Transform;
表循环函数:Table.TransformColumns;记录循环:Record.TransformFields。
循环就是将容器中的元素一个一个的拿出来,依次进行操作,例如我们构建一个{1,2,3}的列表,现在需要将列表中的每个元素都进行*10的运算,如下图
![88b225403137929b1eb20d366e36d27a.png](https://img-blog.csdnimg.cn/img_convert/88b225403137929b1eb20d366e36d27a.png)
代码:= List.Transform({1,2,3}, each _*10)
使用列表循环函数List.Transform,该函数的意思就是将列表{1,2,3}中的每个元素依次循环出来,赋予给后面的下划线,列表有几个元素,该函数就进行几次操作
第一次:循环出列表中的1,赋予给后面的下划线,然后*10,得到10
第二次:循环出列表中的2,赋予给后面的下划线,然后*10,得到20
第三次:循环出列表中的3,赋予给后面的下划线,然后*10,得到30
最终返回得到的新列表{10,20,30}。
循环函数最终得到的元素个数和初始列表的个数一致。
迭代
重复执行一系列运算步骤,从前面的量依次求出后面的量的过程,此过程的每一次结果,都是由对前一次所得结果施行相同的运算步骤得到的。简单的迭代就是累计求和,
Power Query的List.Accumulate就属于迭代函数
![6f65dbc02492b12461a43fc3a8ae7257.png](https://img-blog.csdnimg.cn/img_convert/6f65dbc02492b12461a43fc3a8ae7257.png)
参数一:为需要求和的列表{1,2,3,4,5}
参数二:提供一个初始值0
参数三:有两个变量,x等于每次迭代之后的值,y等于列表中的元素
该函数的运算规律如下:
第一次:x等于我们指定的初始值0,y=1,计算 x+y=> 0+1=1;
第二次:x等于上一次计算的结果1,y=2,计算 x+y=> 1+2=3;
第三次:x等于上一次计算的结果3,y=3,计算 x+y=> 3+3=6;
第四次:x等于上一次计算的结果6,y=4,计算 x+y=> 6+4=10;
List.Accumulate返回最后一次计算的结果,迭代是一种累计循环,最后只有一个值。
这好像看不出有什么厉害,这求和直接List.Sum不就可以了么?在来看一个复杂的例子
需要将列表{1..10}中偶数和奇数分别放在两个列表中,如下图:
![08f94c9004a25097cd43774ae718dd75.png](https://img-blog.csdnimg.cn/img_convert/08f94c9004a25097cd43774ae718dd75.png)
代码:
= List.Accumulate({1..10}, {{},{}},
(x,y)=> if Number.IsEven(y) then {x{0}&{y}, x{1}} else {x{0}, x{1}&{y}})
Number.IsEven判断值是否是偶数
x{0} 深化x中的第一个元素,x{1}&{y}
来分析一下这段代码的运算逻辑,
还的分步骤:
第一次:x等于我们指定的列表 x={{}, {}} , y=1;
判断 Number.IsEven(1)=False,
则执行else后面的代码,{x{0}, x{1}&{y}}
x{0} 深化x中的第一个元素 = {}
x{1}&{y} 深化x中的第二个元素在链接{y} => {}&{1}={1}
最终运算的结果为{x{0}, x{1}&{y}} = {{}, {1}}
第二次:x等于第一次运算的结果 x={{}, {1}},y=2;
判断 Number.IsEven(2)=True,
则执行then后面的代码,{x{0}&{y}, x{1}}
x{0}&{y} 深化x中的第一个元素在链接{y} => {}&{2}={2}
x{1} 深化x中的第二个元素 = {1}
最终运算的结果为{x{0}&{y}, x{1}} = {{2}, {1}}
第三次:x等于第二次运算的结果 x={{2}, {1}} , y=3;
判断 Number.IsEven(3)=False,
则执行else后面的代码,{x{0}, x{1}&{y}}
x{0} 深化x中的第一个元素 = {2}
x{1}&{y} 深化x中的第二个元素在链接{y} => {1}&{3}={1,3}
最终运算的结果为{x{0}, x{1}&{y}} = {{2}, {1,3}}
第四次:x等于第三次运算的结果 x={{2}, {1,3}},y=4;
判断 Number.IsEven(4)=True,
则执行then后面的代码,{x{0}&{y}, x{1}}
x{0}&{y} 深化x中的第一个元素在链接{y} => {2}&{4}={2,4}
x{1} 深化x中的第二个元素 = {1,3}
最终运算的结果为{x{0}&{y}, x{1}} = {{2,4}, {1,3}}
第五次:x等于第二次运算的结果 x={{2,4}, {1,3}} , y=5;
判断 Number.IsEven(5)=False,
则执行else后面的代码,{x{0}, x{1}&{y}}
x{0} 深化x中的第一个元素 = {2,4}
x{1}&{y} 深化x中的第二个元素在链接{y} => {1,3}&{5}={1,3,5}
最终运算的结果为{x{0}, x{1}&{y}} = {{2,4}, {1,3,5}} ......
重点就是x,每次进行计算的时候,x都等于上一次运算的结果。
递归
程序调用自身的编程技巧称为递归,如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归这个概念之前想了很久,没有深刻理解,今天在M群看到一个例题,突然就领悟了。其实递归和迭代很类似,先来看一个简单的递归,如下图:
![9d79f228ce5651450aead19001c7bba2.png](https://img-blog.csdnimg.cn/img_convert/9d79f228ce5651450aead19001c7bba2.png)
会发现这个代码计算结果和上面List.Accumulacte的第一个案例相同,也就是求列表
{1,2,3,4}的和。
@是作用域操作符,引用函数在其范围内,简单来说就是允许函数再次调用本身,从而实现递归。
那么这个递归函数是如何进行计算的么:
给予的参数是x = 4 ,不满足 if 条件,则执行else后面的代码 fx(x-1)+x =>fx(3)+4,
第二次调用函数,x=3,不满足 if 条件,fx(2)+3+4
第三次调用函数,x=2,不满足 if 条件,fx(1)+2+3+4
第四次调用函数,x=1,满足条件,则执行 then后面的代码
最终 fx(4) => 1+2+3+4 =10
关于PQ里面的递归,可以参考施阳的博客,有详细的讲解(想当初看这篇文章的时候,头发掉了一大把)
递归函数 | Power Query爱好者pqfans.com循环+递归
有这样一个题,需要将下面列表中的所有元素*10
![9f1d155663f15e2776ea975e6306edb2.png](https://img-blog.csdnimg.cn/img_convert/9f1d155663f15e2776ea975e6306edb2.png)
所有元素*10,想到的就是循环函数List.Transform,然而会发现列表中嵌套有列表,当循环到列表元素的时候,无法进行计算。
![c88193b8de142951edafff6ff5e838dd.png](https://img-blog.csdnimg.cn/img_convert/c88193b8de142951edafff6ff5e838dd.png)
我们需要继续使用List.Transform函数对子列表中进行循环,这里就可以使用递归
![320e77feefc972ba916c9ac2f3c5c76a.png](https://img-blog.csdnimg.cn/img_convert/320e77feefc972ba916c9ac2f3c5c76a.png)
let
list = {1,2,{3,4,{5,6}},{7,8},9},
fx = (x)=> List.Transform(x, each
if _ is number
then _*10
else @fx(_)
)
in
fx(list)
定义一个递归函数fx(x),循环参数x里面的每一个元素,判断如果元素为数值,则进行*10的运算,如果不是,则用该元素作为参数进入第二次循环 @fx(_)。
迭代+递归
还是上面的例题,现在需要将列表 list = {1,2,{3,4,{5,6}},{7,8},9} 进行求和,同样有嵌套的情况,无法使用List.Sum。
使用迭代+递归的方法来完成,最终结果
![6d5f99d2c5172bd1d1722a7330a1060c.png](https://img-blog.csdnimg.cn/img_convert/6d5f99d2c5172bd1d1722a7330a1060c.png)
let
list = {1,2,{3,4,{5,6}},{7,8},9},
fx = (x)=> List.Accumulate(x,0,(x,y)=>
if y is number
then x+y
else x+@fx(y)
)
in
fx(list)
1+2+3+4+5+6+7+8+9=45
和循环的逻辑一样,依次判断列表中的每个元素,如果是数字则进行累计,如果不是那么进入第二次迭代计算,并与前面的累计结果相加。
当然还有其他方法可以进行求和计算,这里只是为了学习递归,