乐于分享
好东西不私藏

Excel 特殊排序不会做?一个 PQ 实战案例,带你吃透 List.Sort 自定义排序

Excel 特殊排序不会做?一个 PQ 实战案例,带你吃透 List.Sort 自定义排序

数据处理过程中,我们经常需要对数据进行排序,但有时候,常规的“升序”或“降序”无法满足业务需求。我们需要根据指定的规则,对数据进行自定义排序。 

今天用一个经典实操案例,带大家吃透 Power Query 里List.Sort自定义比较器,掌握这套通用模板,往后所有非常规排序需求都能直接套用。

需求

有一个表格,每一行包含若干个范围在 1 至 999 之间的正整数:

目标是:将这些数字任意顺序连接,使得拼接后的结果数值最大。 

最终效果格式下:

处理步骤

  1. 将数据导入到PQ,并且将数据都转换为文本格式,因为我们的比较逻辑是基于字符串拼接的,而非数值大小。

  2. 创建自定义排序规则 

    需求是要求最大数,其实就是需要将数据进行排序,再拼接,使其结果为最大的数。 

    但这个需求常规的排序是无法解决的。举个例子:数字9316,单纯按数值大小看 316 更大,但拼接对比93163169,所以 9 必须排在 316 前面。

    排序规则应该是:任意两数转字符串 a、b,若 a+b > b+a → a 放左边;否则 b 放左边。

    它本质是字典序比较拼接结果,不是单纯比数字本身大小,这也是为什么上一步要将数字转为文本。

比如第一行数据:{44,8,9,316,43,45} 逐个两两对比:

  1. "9"+"8" = "98" > "89" → 9 在前
  2. "9"+"45" = "945" > "459" → 9 在 45 前
  3. "45"+"44"="4544" > "4445" → 45 在 44 前
  4. "44"+"43"="4443" > "4344" →44 在 43 前
  5. "43"+"316"="43316" > "31643" →43 在 316 前
  6. 排序顺序:9,8,45,44,43,316  拼接结果为:98454443316,这也就是能拼接出的最大数。

上面的规则,我们可以用一个自定义函数来表示:

  1. 单行数据转为列表,套用自定义排序规则 
    先将每一行数据,转为列表

再用List.sort进行排序,PQ 的列表排序支持传入自定义比较函数。

将刚才定义的比较逻辑作为第二个参数传递给 List.Sort

List.Sort 在排序时,会自动从列表里随便挑两个元素丢进 fx 做对比:

排序流程:

  • 取出一行所有文本:{"44","8","9","316","43","45"}
  • Sort 会不断两两丢进 fx 对比,根据 fx 返回的 - 1/0 自动调换位置
  • PQ 内置排序引擎自动完成全列表重排
  • 最终排好的顺序:{"9","8","45","44","43","316"}
  1. 合并文本 
    排序完成后,使用 Text.Combine 将列表中的文本合并,即可得到最终的最大数。

最终代码

let    源 = Excel.CurrentWorkbook(){[Name="表1"]}[Content],    更改的类型 = Table.TransformColumns(源,{},each Text.From(_)),    已添加自定义 = Table.AddColumn(更改的类型, "最大数", each [                                                            fx=(x,y)=>if x&y >y&x then -1  else 0,                                                            r=Text.Combine(List.Sort(Record.ToList(_),fx))                                                        ][r])in    已添加自定义

很多人使用 Power Query 只会基础排序,忽略了List.Sort自定义比较器这个万能工具。 

今天的数字拼接案例看似是算法小题,实则提供了一套通用解决方案:

只要原生排序不满足业务逻辑,我们就能自己定义元素对比规则,交给 PQ 自动批量运算,不用手动分步处理,大大的简化复杂数据流程。

往期推荐:

合集:PQ实战案例系列

合集:M函数系列

合集:Python办公自动化实战

如何批量在子文件夹内新建文件夹并移动文件

VBA案例:抽签生成随机对阵

PowerQuery 案例 75:不用转置、不用拆分!笛卡尔积展开,轻松搞定复杂双层表头

PowerQuery 案例 74:还在用辅助列算库存抵扣?用 PQ 一行代码,彻底告别手动拉表!

PowerQuery 案例 73:被这个分组需求逼疯了!连续相同款号不能拆,还要卡数量?!

PowerQuery 案例 72 | 别再手动对齐层级了!这套偷懒绝招治好了我的强迫症

PowerQuery 案例 71:“既要又要还要”?遇到这种数据,千万别再用嵌套公式折磨自己了

还没关注?↑↑↑伸出手指点上方“名片”这里