Scala的理解 - 产生w /复杂的过滤器

时间:2014-05-07 20:08:29

标签: scala declarative for-comprehension

我正在尝试在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]列表。但是,在这种情况下,我不想拥有可选类型。

当然,我只是简单地创建一个可变列表,只在满足条件时才附加到列表中,但是我想看看如何以更多的声明方式执行此操作(并非所有的声明方式)但是,我还在学习!)。

任何有良好声明性方法的建议都会非常有用。

2 个答案:

答案 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中。