3

我正在尝试在 Scala 中构建理解,但是当我尝试使用更复杂的过滤器时遇到了一些问题。

我知道理解过滤的基本知识:

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 理解不允许在过滤器语句中声明 val,否则你必须将所有这些都放在一行中。

另一种选择是根本不使用过滤器机制,只产生 Some(element) 或 None,并最终得到一个 Option[elementType] 列表。但是,在这种情况下,我不想使用 Optional 类型。

当务之急,我只是创建一个可变列表,并且仅在满足我的条件时才附加到列表中,但我想看看如何以更多的声明方式来做到这一点(不是所有的声明方式,但我我还在学习!)。

任何关于好的声明性方法的建议都会非常有帮助。

4

2 回答 2

4

在这种情况下,使用 List 的过滤方法不是最简单的解决方案吗?:

elementList.filter(el => databaseCall.getMatching(el.id).name == el.name)
于 2014-05-07T20:24:21.490 回答
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
 }

正如你所知道的,让 for 理解包含并做所有事情有时会导致相当冗长或令人困惑的陈述。因为理解在使用中应该是可读和直观的。将条件分开,以便您可以组合出您想要的结果,即使这意味着所有逻辑都不会在理解中。

旁注:如果数据库查询可以返回 anull那么更好的方法是将调用包装在Option.

于 2014-05-07T20:18:20.683 回答