You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala字符串列表校验:仅含AA/BB前缀且需同时存在、排除CC

列表校验逻辑的优化方案

需求:校验一个String列表,要求必须同时包含以AA和BB开头的字符串,且列表里只能有AA/BB开头的元素,不能出现CC开头或其他不符合前缀的元素。以下是能正常运行的原实现,想知道有没有更优的写法?

原实现代码

private final val ValidPatternA: String = "^AA.*"
private final val ValidPatternB: String = "^BB.*"
private final val InvalidPatternC: String = "^CC.*"

def main(args: Array[String]): Unit = {
  println(isValid(Seq())) // false
  println(isValid(Seq("AA0"))) // false
  println(isValid(Seq("BB1"))) // false
  println(isValid(Seq("CC2"))) // false
  println(isValid(Seq("AA0", "BB1", "CC2"))) // false
  println(isValid(Seq("AA0", "CC2"))) // false
  println(isValid(Seq("BB1", "CC2"))) // false
  println(isValid(Seq("AA0", "BB1"))) // true
}

private def isValid(listOfString: Seq[String]) =
  !listOfString.exists(_.matches(InvalidPatternC)) &&
    listOfString.exists(_.matches(ValidPatternA)) &&
    listOfString.exists(_.matches(ValidPatternB))

原代码的问题

  1. 逻辑漏洞:没校验所有元素都是AA/BB开头,比如Seq("AA0", "BB1", "DD3")会被误判为有效
  2. 效率浪费:三次调用exists会遍历列表三次
  3. 正则冗余:前缀匹配用正则有点大材小用,不如直接用startsWith高效

优化后的实现

方案1:命令式风格(高效且直观)

一次遍历完成所有校验,遇到无效元素直接提前返回:

def main(args: Array[String]): Unit = {
  println(isValid(Seq())) // false
  println(isValid(Seq("AA0"))) // false
  println(isValid(Seq("BB1"))) // false
  println(isValid(Seq("CC2"))) // false
  println(isValid(Seq("AA0", "BB1", "CC2"))) // false
  println(isValid(Seq("AA0", "CC2"))) // false
  println(isValid(Seq("BB1", "CC2"))) // false
  println(isValid(Seq("AA0", "BB1"))) // true
  println(isValid(Seq("AA0", "BB1", "DD3"))) // false  // 修复原代码的漏洞
}

private def isValid(listOfString: Seq[String]): Boolean = {
  if (listOfString.isEmpty) return false
  
  var hasAA = false
  var hasBB = false
  
  for (s <- listOfString) {
    val isAA = s.startsWith("AA")
    val isBB = s.startsWith("BB")
    
    // 遇到CC直接无效
    if (s.startsWith("CC")) return false
    // 既不是AA也不是BB,直接无效
    if (!isAA && !isBB) return false
    
    if (isAA) hasAA = true
    if (isBB) hasBB = true
  }
  
  // 必须同时存在AA和BB
  hasAA && hasBB
}

方案2:函数式风格(无变量)

如果偏好纯函数式写法,用foldLeft累积状态:

private def isValid(listOfString: Seq[String]): Boolean = {
  val (hasAA, hasBB, hasInvalid) = listOfString.foldLeft((false, false, false)) {
    case ((a, b, invalid), s) =>
      if (invalid) (a, b, true) // 已有无效元素,直接传递状态
      else if (s.startsWith("CC")) (a, b, true)
      else {
        val newA = a || s.startsWith("AA")
        val newB = b || s.startsWith("BB")
        val newInvalid = !(s.startsWith("AA") || s.startsWith("BB"))
        (newA, newB, newInvalid)
      }
  }
  
  // 非空、无无效元素、同时有AA和BB
  listOfString.nonEmpty && !hasInvalid && hasAA && hasBB
}

优化点总结

  • 性能提升:一次遍历替代三次遍历,startsWith比正则前缀匹配更快
  • 逻辑严谨:补上了原代码未校验非AA/BB元素的漏洞
  • 提前终止:遇到无效元素立刻返回,不用遍历完整个列表
  • 代码可读性:逻辑直白,比正则更容易理解

内容的提问来源于stack exchange,提问作者Wonderboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 01:06:20