Scala集合:遍历列表时如何携带状态处理重复元素?
解决Scala中带状态修改列表重复元素的问题
嘿,这个需求我太熟了!确实map方法完全满足不了,因为它是无状态的——每处理一个元素时,根本没法记住之前已经出现过多少次相同的元素。要实现给重复元素加序号的效果,我们得用带状态的遍历方法,比如foldLeft,它能帮我们在遍历过程中维护一个累加器来跟踪状态。
需求回顾
输入列表:
val l1 = List("a","b","c","d","e","f","b","c","e","b","a")
期望输出:List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)
规则:只有出现次数大于1的元素,每次出现都加上当前的出现序号;仅出现一次的元素保留原样。
解决方案代码
// 第一步:先统计每个元素的总出现次数,用来判断是否需要加序号 val l1 = List("a","b","c","d","e","f","b","c","e","b","a") val elementTotalCounts = l1.groupBy(identity).view.mapValues(_.size).toMap // 第二步:用foldLeft维护状态遍历列表 val (finalResult, _) = l1.foldLeft((List.empty[String], Map.empty[String, Int])) { case ((resultAccumulator, currentCountMap), elem) => // 获取当前元素已经出现的次数,加1得到本次的序号 val currentOccurrence = currentCountMap.getOrElse(elem, 0) + 1 // 判断是否需要加序号:总次数>1则拼接,否则保留原元素 val modifiedElem = if (elementTotalCounts(elem) > 1) s"$elem$currentOccurrence" else elem // 更新累加器:把新元素加入结果列表,更新计数Map (resultAccumulator :+ modifiedElem, currentCountMap + (elem -> currentOccurrence)) } // 输出结果就是你想要的 println(finalResult) // 输出:List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)
代码解释
elementTotalCounts:通过groupBy把相同元素分组,再统计每组的大小,得到每个元素的总出现次数。这一步是为了区分“需要加序号的元素”和“不需要加序号的元素”(比如d、f只出现一次,就不用加)。foldLeft的累加器:我们用一个元组(List[String], Map[String, Int])作为累加器,前者存处理后的结果,后者存每个元素当前已经出现的次数。- 每次遍历的逻辑:
- 先计算当前元素这次是第几次出现;
- 根据总出现次数判断是否要加序号;
- 更新结果列表和计数Map,继续下一次遍历。
这种方法的优势是只需要遍历列表两次(一次统计次数,一次处理元素),效率很高,而且逻辑清晰,完全满足带状态修改的需求。
内容的提问来源于stack exchange,提问作者West_JR
相关产品推荐
相关产品推荐

