在Scala中映射/保护结构的过滤器/地图结构

时间:2015-08-27 22:18:55

标签: regex scala dictionary filter

我有一个summaryPool可变映射,它将String映射到Summary对象。 函数namesToSummary有两个参数,第一个是一系列名称(在Iterable [String]中),第二个是summaryPool。它的作用是返回一系列对应名称的摘要。

它有点复杂,因为应该使用正则表达式检查名称,以提取曾经是summaryPool关键字的信息。

例如," summary1b"应该检查以获得" summary1"和" b&#34 ;; "摘要1"是游泳池的关键。在某些情况下,可能没有" b"追加。

我的实现使用isSummaryPool函数来过滤掉格式错误的名称,或者不在池中的名称。然后,我使用map来获取池中Summary对象的副本。

  import scala.collection.mutable.{Map => mm}
  def namesToSummaries(names: Iterable[String], summaryPool: mm[String, Summary]) = {
    val namePattern = """([a-zA-Z]+\d+)([a-z])?""".r
    def inSummaryPool(name: String) = {
      name match {
        case namePattern(summaryName, summaryType) => {
          if (summaryPool.contains(summaryName)) true
          else false
        }
        case _ => false
      }
    }

    names filter inSummaryPool map { name =>
      name match {
        case namePattern(summaryName, summaryType) => {
          var sType = summaryType
          if (sType == null || !(sType == "b" || sType == "l")) sType = "b"
          summaryPool.get(summaryName).get.copy(sType)
        }
      }
    }
  }

它工作正常,但我不喜欢实现,因为它检查正则表达式匹配两次。

我想我可以将过滤器/地图与警卫整合到地图中。为了做到这一点,我瘦我可能需要实现类似于此:

  import scala.collection.mutable.{Map => mm}
  def namesToSummaries(names: Iterable[String], summaryPool: mm[String, Summary]) = {
    val namePattern = """([a-zA-Z]+\d+)([a-z])?""".r

    names map { name =>
      name match {
        case namePattern(summaryName, summaryType) => {
          if (summaryPool.contains(summaryName)) {
            var sType = summaryType
            if (sType == null || !(sType == "b" || sType == "l")) sType = "b"
              summaryPool.get(summaryName).get.copy(sType)
          }
          else 
            ???
        }
        case _ => ???
      }
    }
  }

我不确定应该在???中给出什么表达式?教Scala忽略这些案例。

可能是什么解决方案?

EDIT1

我可以考虑在必要时使ListBuffer对象添加Summary对象。 但是,当模式不匹配时,我不确定这种情况。

    val list: ListBuffer
    names foreach { name =>
      name match {
        case namePattern(summaryName, summaryType) => {
          if (summaryPool.contains(summaryName)) {
            var sType = summaryType
            if (sType == null || !(sType == "b" || sType == "l")) sType = "b"
              list += summaryPool.get(summaryName).get.copy(sType)
          }
        }
        case _ => ???
      }
    }
  }

EDIT2

来自Shadowlands'回答,flatMap with None return工作正常。

def namesToSummaries(names: Iterable[String], summaryPool: mm[String, Summary]) = {
    val namePattern = """([a-zA-Z]+\d+)([a-z])?""".r
    names flatMap { name =>
        name match {
            case namePattern(summaryName, summaryType) => {
                if (summaryPool.contains(summaryName)) {
                    var sType = summaryType
                    if (sType == null || !(sType == "b" || sType == "l")) sType = "b"
                    Some(summaryPool.get(summaryName).get.copy())
                }
                else None
            }
            case _ => None
        }
    }
}

EDIT3

从Jilen的提示来看,collect似乎是减少更多代码行的好答案。

def namesToSummaries(names: Iterable[String], summaryPool: mm[String, Summary]) = {
    val namePattern = """([a-zA-Z]+\d+)([a-z])?""".r
    names collect { name =>
        name match {
            case namePattern(summaryName, summaryType) if (summaryPool.contains(summaryName)) => {
                var sType = summaryType
                if (sType == null || !(sType == "b" || sType == "l")) sType = "b"
                  summaryPool.get(summaryName).get.copy()
            }
        }
    }
}  

但是,IntelliJ 14中的此代码显示误报错误:这是错误报告(https://youtrack.jetbrains.com/issue/SCL-9094#)。

1 个答案:

答案 0 :(得分:1)

不要在名称上调用map,而是尝试使用flatMap。在Some(...)中包裹您的成功案例,???变为None。 flatMap的'flattening'部分会将'映射'Iterable[Option[String]]缩减回Iterable[String],从而放弃所有None个案例。

编辑:我没有足够仔细地钻进你的代码 - 在'成功'的情况下,你似乎做了纯粹的副作用(即更新可变图),而不是返回任何类型的结果。

您可以在此时返回(summaryName, summaryType)元组(包含在Some中)并将副作用代码应用于生成的flatMap的内容(可能是我的偏好)一个稍微更具功能性的风格),或者只是回到使用地图,只需写_(意思是这里:'什么也不做 - 忽略任何结果')而不是???