Лучшая версия "итерации по Seq или пустой" в scala?

Существует ли более короткий/лучший способ сделать следующее:

mySeq.map { elmt => 
    // do stuff
}   

if (mySeq.isEmpty) {
    // some other stuff
}

Ps: Я использую PlayFramework, и это предназначено для использования в шаблонах, поэтому, если есть какие-то "помощники", которые я пропустил, я был бы рад узнать их;)

Ответ 1

Как насчет этого?

mySeq.headOption.map { _ =>
  mySeq.map { elmt => 
    // do stuff
  }
}.getOrElse {
  // some other stuff
}

Ответ 2

Вы можете использовать match:

l match {
  case l if !l.isEmpty => l.map{ // do stuff }
  case _ => // some other stuff
}

Для List:

l match {
  case h :: t => l.map{ // do stuff }
  case _ => // some other stuff
}

В качестве альтернативы вы можете определить свой собственный метод:

import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike

class FoldEmpty[T, S[T] <: TraversableLike[T, S[T]]](l: S[T]){
  def foldEmpty[B, That](notEmpty: T => B, empty: => That)(implicit cbf: CanBuildFrom[S[T], B, That]): That = 
    l match {
      case t if !t.isEmpty => l map notEmpty
      case _ => empty
    }
}

implicit def seqToFoldEmpty[T, S[T] <: TraversableLike[T, S[T]]](l: S[T]) = new FoldEmpty(l)

Использование:

scala> IndexedSeq(1, 2, 3).foldEmpty( _ + 1 , IndexedSeq(-1))
res0: IndexedSeq[Int] = Vector(2, 3, 4)

scala> IndexedSeq[Int]().foldEmpty( _ + 1 , Seq(-1))
res1: Seq[Int] = List(-1)

Ответ 3

Недавно я gisted помощник, который генерирует некоторый HTML, только если данная последовательность не пуста. Поместите это небольшое изменение в файл, например. Helpers.scala:

package views.html.helper

import play.api.templates.Html

object nonEmptyOrElse {
  def apply[T <: Seq[_]](t: T)(nonEmptyBlock: (T) => Html)(emptyBlock: => Html) = {
    if (t.nonEmpty) nonEmptyBlock(t) else emptyBlock
  }
}

И используйте его как в шаблоне:

@nonEmptyOrElse(mySeq) { seq =>
  //doSomething with entire seq
} {
  // do something else
}

Изменить: И вот версия отображает каждый элемент:

object mapOrElse {
  def apply[T](t: Seq[T])(nonEmptyBlock: (T) => Html)(emptyBlock: => Html) = {
    if (t.nonEmpty) t.map(nonEmptyBlock(_)) else emptyBlock
  }
}

Ответ 4

Имея следующее простое расширение в области видимости:

(для Scala 2.10):

implicit class AnyExtensions[A] ( val x : A ) extends AnyVal {
  def asSatisfying(p: A => Boolean): Option[A] =
    if (p(x)) Some(x) else None
}

(для Scala 2.9):

implicit def anyExtensions[A] (x : A) = new {
  def asSatisfying(p: A => Boolean): Option[A] =
    if (p(x)) Some(x) else None 
}

вы сможете переписать свой код следующим образом:

mySeq
  .asSatisfying{_.nonEmpty}
  .map{
    _.map{elmt => 
      // do stuff
    }
  }
  .getOrElse{
    // some other stuff
  }

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

List(1, 2, 3).mkString(", ").asSatisfying{_.nonEmpty}.getOrElse("Empty list")

Это приведет к String 1, 2, 3 и приведет к String Empty list, если список пуст.