我有一个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忽略这些案例。
可能是什么解决方案?
我可以考虑在必要时使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 _ => ???
}
}
}
来自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
}
}
}
从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#)。
答案 0 :(得分:1)
不要在名称上调用map
,而是尝试使用flatMap
。在Some(...)
中包裹您的成功案例,???
变为None
。 flatMap的'flattening'部分会将'映射'Iterable[Option[String]]
缩减回Iterable[String]
,从而放弃所有None
个案例。
编辑:我没有足够仔细地钻进你的代码 - 在'成功'的情况下,你似乎做了纯粹的副作用(即更新可变图),而不是返回任何类型的结果。
您可以在此时返回(summaryName, summaryType)
元组(包含在Some
中)并将副作用代码应用于生成的flatMap
的内容(可能是我的偏好)一个稍微更具功能性的风格),或者只是回到使用地图,只需写_
(意思是这里:'什么也不做 - 忽略任何结果')而不是???
。