我正在尝试在Scala中构建一个for comprehension,但在尝试使用更复杂的过滤器时遇到了一些问题。
我知道理解过滤的基本知识:
for (x <- 1 until 20 if x>3) yield {
x
}
但是,我想构建一个具有更复杂的过滤语句的for comprehension。例如,这是我尝试做的一个说明性版本:
for (
element <- elementList
val otherElement = databaseCall.getMatching(element.id)
if element.name==otherElement.name
) yield {
element
}
基本上,如果你想要一个带有更复杂要求的过滤器,这会变得很尴尬,因为for comprehension不允许在过滤器语句中声明val,否则你必须适合那个所有一行。
另一种方法是根本不使用过滤器机制,只是产生Some(元素)或None,最后得到Option [elementType]列表。但是,在这种情况下,我不想拥有可选类型。
当然,我只是简单地创建一个可变列表,只在满足条件时才附加到列表中,但是我想看看如何以更多的声明方式执行此操作(并非所有的声明方式)但是,我还在学习!)。
任何有良好声明性方法的建议都会非常有用。
答案 0 :(得分:4)
在这种情况下,使用List的过滤方法不是最简单的解决方案吗?:
elementList.filter(el => databaseCall.getMatching(el.id).name == el.name)
答案 1 :(得分:1)
看起来你正在做一些带副作用的地图。这些副作用可能会导致异常,从而导致您可能希望避免的结果列表。因此,在你想要做的事情范围内使用一个关闭你正在尝试做的事情:
def outerScope(elementList: List[YourType]): List[YourType] =
def dbAction(element: YourType): Option[YourType] = try{
val other = databaseCall getMatching element.id //assuming can't return null
if(other.name == element.name) Some(element) else None
}
catch{
case ex: Exception => None //don't forget to log it
}
for{
elem <- elementList
value <- dbAction(elem)
} yield value
}
正如你已经想到的那样,让理解包含并做所有事情有时会导致相当冗长或混乱的陈述。因为理解应该是可读和直观的使用。将条件分开,以便你可以对你想要的结果进行组合,即使这意味着所有的逻辑都不会理解。
旁注:如果数据库查询可以返回null
,那么更好的方法是将调用包装在Option
中。