Scala для понимания - yield со сложным фильтром

Я пытаюсь создать на Scala для понимания, но сталкиваюсь с некоторыми проблемами, когда пытаюсь использовать более сложный фильтр.

Я знаю основы фильтрации понимания:

for (x <- 1 until 20 if x>3) yield {
  x
}

Однако я хочу создать для понимания, в котором есть гораздо более сложный оператор фильтрации. Например, вот иллюстративная версия того, что я пытаюсь сделать:

for (
    element <- elementList
    val otherElement = databaseCall.getMatching(element.id)
    if element.name==otherElement.name
) yield {
  element
}

По сути, если вы хотите создать фильтр с более сложными требованиями, это становится неудобно, потому что for complation не позволяет объявлять vals в операторе фильтра, и в противном случае вам пришлось бы уместить все это в одну строку.

Альтернативой было бы вообще не использовать механизм фильтрации, а просто выдать Some (element) или None и вместо этого получить список Option [elementType]. Однако я не хочу, чтобы в этом случае были необязательные типы.

В обязательном порядке я бы просто создал изменяемый список и добавил бы к нему только тогда, когда мое условие выполнено, но я хочу увидеть, как это сделать в большей степени декларативным образом (еще не полностью декларативным, но я '' м еще учусь!).

Любые предложения хороших декларативных способов сделать это были бы очень полезны.


person Shookit    schedule 07.05.2014    source источник
comment
Я не понимаю, что вы имеете в виду, понимая, что нельзя объявлять vals в заявлении фильтра. Мои тесты в REPL показывают, что это так, хотя val теперь не нужен и устарел.   -  person wingedsubmariner    schedule 08.05.2014
comment
Фактически вы можете назначить переменную внутри для понимания, посмотрите это   -  person Ende Neu    schedule 08.05.2014


Ответы (2)


Не является ли использование метода фильтрации списка самым простым решением в этом случае ?:

elementList.filter(el => databaseCall.getMatching(el.id).name == el.name)
person Roel Van der Paal    schedule 07.05.2014
comment
Ух, извините за то, что приставил к вам, ребята, надеюсь, это будет кому-то полезно. Это то, что я искал; У меня в голове было, что for comp - это просто синтаксический сахар вокруг фильтра и карты, поэтому я даже не подумал вернуться к этому. К сожалению, я все еще придерживаюсь императивного мышления. - person Shookit; 08.05.2014

Похоже, вы делаете что-то, что является картой с побочными эффектами. Эти побочные эффекты могут привести к исключениям, которые, в свою очередь, могут привести к списку результатов, которого вы, вероятно, хотели бы избежать. Так что используйте закрытие вокруг того, что вы пытаетесь сделать, в рамках того, что вы хотите сделать:

 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.

person wheaties    schedule 07.05.2014