一直以来,我都在设想找一些相对简单而又能多练几个函数的案例,当在群里看到本文中需求的时候,突然脑洞大开,基于这个问题,将Power Query的List类和Text类常用函数给撸了一遍,写了15种解法,有简单有复杂,也不考虑孰优孰劣,供需要进一步熟悉这些常用函数的朋友加以练习。
问题如下:
- 有一个产品名称(实际工作中当然是很多的,此仅以一个为例)
- 有一堆常见的搜索关键词
- 希望知道哪些搜索关键词都被包含在了这个产品名称中(实际数据分析中常常以此方法来判断某个产品名称的综合搜索人气或热度)
如下图所示:
为简化问题,本练习只考虑搜索词中的每个字是否都被标题所包含,若都包含,则匹配度为100%(或只标注为true即可),否则匹配度按被包含的字数和搜索词本身的字数之间的比例计算(或只标注为false即可)。
需要结果如下(两种方式都可接受):
如果到这里感觉还没看懂问题,那就直接到案例中看吧。
下面开始15个不同的解法及简要说明。
1、找出两者都有的字(交集)并计数(记录式写法)
思路很明确,先将标题和搜索词拆成字列表(Text.ToList),再用List.Intersect获得两个列表中都有的字(交集),最后用List.Count函数得到相应的字数进行相除,求得匹配度。
2、找出两者都有的字(交集)并计数(函数嵌套式写法)
思路跟方法1基本一样,但因为直接用函数嵌套的方式,所以为避免最后计算搜索词长度时再次拆分(方法1中因为用字段b得到了搜索词的拆分列表,因此后面可以直接用List.Count取得长度),所以直接用Text.Length函数计算长度。
3、将未被标题包含的字转为null,并计算转换后的非null值的个数
通过List.Transform函数对拆分的搜索词列表进行转换,如果搜索词的某个字被标题所包含,则保留原样,如果没有被标题所包含,则转为null值。这样,列表转换后就可以用List.NonNullCount函数统计其中有多少个非null的值。
4、将未被标题包含的字转为0,被包含的转为1,然后求和
思路跟方法3类似,通过List.Transform函数对拆分的搜索词列表进行转换,如果搜索词的某个字被标题所包含,则转为1,如果没有被标题所包含,则转为0。这样,列表转换后就可以用List.Sum函数求和。
5、基于搜索词进行累积处理,若某字被包含,则累积到列表中
用List.Accumulate的累积计算替代List.Transform的列表转换方法,其他内容类似。其中List.Accumulate函数的运行机制稍微复杂,但该函数功能比较强大,后续再通过更多的例子专门讲解。
6、使用TransformMany函数直接转换为1或0,然后进行求和
List.TransformMany函数可以实现将1个列表的元素转换为一个新列表,然后再对旧列表和新列表进行综合的运算。这里用比较简单,直接将搜索词列表转换为是否包含相应搜索词的新列表,然后对新列表进行判断生成1或0的序列——旧列表(o,n)中的o不需要使用。
7、使用List.Generate构造出1,0判断结果列表然后求和
思路仍然是针对关键词的每个字,如果被包含就得到1,不包含就得到0,但通过List.Generate构造出来,这个函数的使用相对复杂一些,后续专门撰文讲解。
8、判断关键词中的每个字是否都被包含
核心仍然是用List.Transform函数对关键词中的每个字进行判断,转换为true或false列表,然后用List.AllTrue函数判断是否都为true(包含)。
9、直接判断某个List是否全包含另一个List
将内容和搜索词均转换为列表,然后用List.ContainsAll函数判断内容列表是否全包含搜索词列表。这个最判断最简单直接。
10、将内容和搜索词组合并后再和原来的内容(均删重复)进行比较
如果搜索词都包含在内容中,那么两者合并后的内容不会增加新的字眼,因此删重复后仍然和原来的内容(删重复)一致。
11、用List.MatchesAll函数判断搜索词中的每个字是否都在内容中
List.MatchesAll函数允许对一个列表进行判断,看这个列表是否都满足某一个条件,这里即对搜索词的每一个字进行判断,看其中每一个字是否都满足条件——包含在相应的内容中。
12、按条件对搜索词列表进行删除,看是否会被删空
List.Skip函数可以按条件对列表的内容进行跳过(删除),从而保留未满足条件的项目,在这里可以对搜索词进行相应的处理:即如果搜索词的某个字在内容中,则跳过(删除),最后看是否会被全部删掉而得到一个空列表。
13、直接删除列表的匹配内容,看是否会被删空
思路和上面用List.Skip类似,但直接用List.RemoveMatchingItems来实现,即参照内容列表对搜索词进行删除,最后如果删成空的,那也说明搜索词里的每个字都能在内容里找到。
14、用函数List.RemoveItems直接删除列表的匹配内容,看是否会被删空
在这个问题里,List.RemoveItems函数和List.RemoveMatchingItems的用法基本一样,关于这两个函数的区别,后续专门撰文讲解。
15、直接按内容列表删除搜索词的文本内容,看是否会被删空
既然可以直接用删除的方法进行判断,那当然也可以直接用文本删除的方式来判断,只是文本删空后是"",而列表删空后是{}。
以上通过15种方法来实现了同一个目标,涉及到的函数包括:
- Text.ToList
- List.Intersect
- List.Count
- Text.Length
- List.NonNullCount
- List.Transform
- Text.Contains
- List.Sum
- List.Accumulate
- List.Combine
- List.TransformMany
- List.Generate
- Text.Middle
- List.AllTrue
- List.ContainsAll
- List.Union
- List.Distinct
- List.MatchesAll
- List.Skip
- List.RemoveMatchingItems
- List.RemoveItems
- Text.Remove
其中相对复杂的函数是List.Accumulate和List.Generate,还有些用法或概念上比较类似的函数,比如List.RemoveMatchingItems和List.RemoveItems,List.MatchesAll和List.AllTrue等,这些我后续会用更多案例进行分享。