在scala中更好的“迭代Seq或如果为空”的版本?

时间:2012-08-21 08:31:43

标签: scala playframework-2.0

是否有更短/更好的方法来执行以下操作:

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

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

Ps:我正在使用PlayFramework,这是用于模板,所以如果有任何“助手”我错过了,我会很高兴发现那些;)

5 个答案:

答案 0 :(得分:13)

这个怎么样?

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

答案 1 :(得分:6)

您可以使用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)

答案 2 :(得分:4)

我最近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
  }
}

答案 3 :(得分:2)

在范围内具有以下简单扩展名:

(对于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

答案 4 :(得分:0)

这是一个有用的值类,如果Seq.isEmpty可以将Seq [A]转换为None,否则将其包装在Some [Seq [A]]中。

对于Scala 2.10:

  /**
   * A value type class to add some useful utility methods to Seq
   *
   * @param underlying The Seq to augment.
   */
 implicit class SeqExt[+A](private val underlying: Seq[A]) extends AnyVal {

   /** If this Seq is empty, returns None, otherwise builds a new collection by
     * applying a function to all elements of this immutable sequence, and wraps
     * the Seq in an Option.
     *
     * @tparam B   The element type of the returned collection.
     * @param f    The function to apply to each element.
     * @return     If this Seq is empty, returns None, otherwise builds a new collection by
     *             applying a function to all elements of this immutable sequence, and wraps 
     *             the Seq in an Option.
     */
   def mapOption[B](f: (A) ⇒ B): Option[Seq[B]] = {
     if(underlying.isEmpty) None else Some(underlying.map(f))
   }
 }

用法(如您的示例):

mySeq
  .mapOption { elmt => 
    // do stuff to each element if mySeq.nonEmpty
  } 
  .getOrElse {
      // some other stuff if mySeq.isEmpty
  }