从一个单元素Scala集合中获取元素



学习Scala和我一直想要一个与LINQ的Single()方法等效的方法。示例,

val collection: Seq[SomeType]
val (desiredItem, theOthers) = collection.partition(MyFunc)
desiredItem.single.doSomething
         // ^^^^^^

我可以使用desiredItem.head,但如果MyFunc真的匹配了几个呢?我要保证只有一个。

编辑#2重复的问题说"不,没有,但下面是如何构建它"。所以我想,如果这是一个普遍的需要,它将是在基础API。正确编写的Scala程序需要这个吗?

我会使用更详细的东西,而不是single:

 (desiredItem match {
   case Seq(single) => single
   case _ => throw IllegalStateException("Not a single element!")
 }).doSomething

它相对于single的优势在于,它允许您在异常情况下显式控制行为(trow an exception,返回回退值)。

或者,您可以使用析构函数赋值:

val Seq(single) = desiredItem
single.doSomething

在这种情况下,如果desiredItem不包含恰好一个元素,则会得到MatchError

UPD:我再次查看了您的代码。破坏任务是你的出路:

val collection: Seq[SomeType]
val (Seq(desiredItem), theOthers) = collection.partition(MyFunc)
desiredItem.doSomething

API中没有预构建的方法可以做到这一点。不过,您可以创建自己的方法来做类似的事情。

scala> def single[A](xs: List[A]) = xs match{ 
 | case List() => None
 | case x::Nil => Some(x)
 | case x::xs => throw new Exception("More than one element")
     | }
single: [A](xs: Seq[A])Option[A]
scala> single(List(1,2,3))
java.lang.Exception: More than one element
  at .single(<console>:11)
  ... 33 elided
scala> single(List(1))
res13: Any = Some(1)
scala> single(List())
res14: Any = None

与其他说明一样,您所寻求的内容没有库实现。但是使用Pimp My Library方法很容易实现您自己的方法。例如,您可以执行以下操作。

object Main extends App {
    object PML {
      implicit class TraversableOps[T](val collection: TraversableOnce[T]) {
        def single: Option[T] = collection.toList match {
          case List(x) => Some(x)
          case _ => None
        }
      }
    }
    import PML._
    val collection: Seq[Int] = Seq(1, 2)
    val (desiredItem, theOthers) = collection.partition(_ < 2)
    println(desiredItem.single)  // Some(1)
    println(collection.single)   // None
    println(List.empty.single)   // None
}

最新更新