首页 文章

将Seq [T]转换为选项[Seq [T]]

提问于
浏览
1

Scala Seq包含对于空序列非法或未定义的方法,例如max

为了保护自己,我经常通过将序列包装在一个选项中并将空映射到None来解决问题 . 它可以这样做:

def wrap[T](s: Seq[T]): Option[Seq[T]] =
    s.headOption map { _ => s }

它也可以通过模式匹配或if-else来解决 .

这些方法都不容易以流畅的方式使用,坦率地说看起来有点尴尬 .

我希望能够做到这样的事情:

someStore
   .giveMeASequence
   .wrapInOption map { nonEmpty:Seq[T] =>
      nonEmpty.max
    } map (_ + 42)

我很犹豫在Try monad中包装操作,因为可以预测和避免异常 .

我是以错误的方式解决问题了吗?

如果没有,是否有任何库方法可供我减少尴尬?

3 回答

  • 3

    正如我在评论中提到的,scalaz NonEmptyList 类可能对您有所帮助 . 通过导入scalaz pimping,您可以访问 toNel 方法,您可以在 List 上调用该方法 . 如果此列表确实为空,则无法继续映射它 . 如果它不是空的,你确实可以映射它 . 请考虑以下示例:

    import scalaz._
    import Scalaz._
    
    val nonEmpty = List(1,2,3)
    val result = 
      nonEmpty.
        toNel.
        map(_.list.max).
        map(_ + 42)
    
    println(result)
    

    如果您运行此代码,它将打印 Some(45) . 如果该列表为空,则会产生 None .

  • 3

    如果您只想进行转换,为什么不使用if / else?

    def wrap[A](s: Seq[A]) = if (s.isEmpty) None else Some(s)
    

    或者,您可以定义自己的 maxOpt 方法:

    implicit def seqWithMaxOpt[A:Ordering](s:Seq[A]) =
      new { def maxOpt = Try(s.max).toOption }
    

    并称之为

    val s:Seq[Int] = Seq()
    s.maxOpt
    

    以同样的方式,您可以添加一个包装选项中序列的方法:

    implicit def seqWithOptionWrapping[A](s:Seq[A]) =
      new { def wrapInOption = if (s.isEmpty) None else Some(s) }
    
  • 3

    您可以通过隐式类使用安全方法扩展 Seq

    implicit class SafeSeq[T](s: Seq[T]) {
        def safeMax(implicit cmp: Ordering[T]): Option[T] =
          if (s.isEmpty) None
          else Some(s.max)
    
        //other safe operations you want
      }
    
      println(Seq.empty[Int].safeMax.map(_ + 42)) // None
      println(Seq(1).safeMax.map(_ + 42))         // Some(43)
    

相关问题