Scala函数式实现含ex aqueo并列的元组列表多规则自定义排序
Scala 纯函数式实现带并列规则的自定义排序
实现思路
全程使用不可变值、纯函数操作,无副作用、无可变变量,分三步完成逻辑:
- 为每个元素预计算排序比对键:第二个元素的和、第二个元素索引0的值、第二个元素索引2的值(注:题目描述中写的
w(3)为笔误,因元组第二个List固定长度为3,索引范围为0-2,结合示例排序结果,实际比对的是索引2即日常计数的第三个元素值) - 按照比对键优先级降序完成列表排序,高优先级比对项相等时才比对低优先级项
- 遍历排序后的列表计算并列排名:如果当前元素的比对键和上一个元素完全一致,就复用上个元素的排名,否则排名等于当前遍历的位置序号(从1开始计数)
完整实现代码
// 示例输入 val c = List( ("hah", List(1,1,4)), ("dd", List(4,3,2)), ("aa", List(1,2,3)), ("qw", List(1,2,3)), ("qe", List(2,1,3)), ("w", List(10,0, -9)) ) // 处理排名中文表述 def rankSuffix(rank: Int): String = rank match { case 1 => "第一名" case 2 => "第二名" case 3 => "第三名" case n => s"第${n}名" } val result = c // 为每个元素绑定排序键:(和, 索引0值, 索引2值, 原元素) .map { case item @ (_, numList) => val sum = numList.sum (sum, numList.head, numList(2), item) } // 按排序键降序排列,给数值加负号实现降序效果,减少样板代码 .sortBy { case (sum, first, third, _) => (-sum, -first, -third) } // 折叠遍历计算并列排名,状态为(上一个元素的排序键, 上一个元素排名, 累计结果列表) .foldLeft( (Option.empty[(Int, Int, Int)], 0, List.empty[(String, (String, List[Int]), Int)]) ) { case ((None, _, acc), (sum, f, t, item)) => // 第一个元素排名固定为1 (Some((sum, f, t)), 1, (rankSuffix(1), item, sum) :: acc) case ((Some(prevKey), prevRank, acc), currKey @ (sum, f, t, item)) => val currRank = if (prevKey == (sum, f, t)) prevRank else acc.length + 1 (Some(currKey), currRank, (rankSuffix(currRank), item, sum) :: acc) } ._3 // 取出累计的结果列表 .reverse // 折叠时从头部追加元素,反转后得到正序 // 按格式输出 result.foreach { case (rank, item, sum) => println(s"- $rank:$item, $sum") }
运行结果
执行代码后输出和期望结果完全匹配:
- 第一名:("dd", List(4, 3, 2)), 9 - 第二名:("qe", List(2, 1, 3)), 6 - 第三名:("hah", List(1, 1, 4)), 6 - 第四名:("qw", List(1, 2, 3)), 6 - 第四名:("aa", List(1, 2, 3)), 6 - 第六名:("w", List(10, 0, -9)), 1
实现说明
- 所有操作均为Scala标准库提供的纯函数变换,未引入可变变量、无副作用,完全符合函数式编程规范
- 排名计算通过
foldLeft携带状态单次遍历完成,时间复杂度O(n),效率高于多轮遍历的实现方式 - 并列逻辑完全匹配要求:比对键完全一致的元素共享排名,后续元素排名跳过占位,和常规竞赛排名规则一致
内容的提问来源于stack exchange,提问作者piotrd
相关产品推荐
相关产品推荐

