/ / ¿Mejor versión de "iterar sobre Seq o si está vacía" en Scala? - Scala, playframework-2.0

¿Mejor versión de "iterar sobre Seq o si está vacía" en scala? - scala, playframework-2.0

¿Hay una forma más corta / mejor de hacer lo siguiente:

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

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

Ps: Estoy usando PlayFramework y esto está destinado a ser usado en plantillas, por lo que si hay algún "ayudante" que extrañe, me encantaría descubrirlo;)

Respuestas

12 para la respuesta № 1

¿Qué tal esto?

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

4 para la respuesta № 2

Puedes usar match:

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

por List:

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

Alternativamente puedes definir tu propio método:

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)

Uso:

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)

4 para la respuesta № 3

Yo recientemente gisted un ayudante que genera algo de HTML solo si la secuencia dada no está vacía. Ponga esta ligera variación en un archivo, por ej. 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
}
}

Y úsalo así en tu plantilla:

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

Edit: Y aquí está la versión que mapea cada elemento:

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

2 para la respuesta № 4

Teniendo la siguiente extensión simple en alcance:

(para 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
}

(para Scala 2.9):

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

Podrá reescribir su código de la siguiente manera:

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

En mi práctica, esta extensión resultó ser aplicable en muchos casos y muy útil. Sobresale en situaciones cuando te das cuenta de que necesitas un if declaración en medio de una expresión, que sin esta extensión habría requerido que introduzcas una variable temporal. Aquí hay un ejemplo:

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

Resultará en un String 1, 2, 3 y habría resultado en una String Empty list si la lista estaba vacía