如何按字母顺序对Option [String]的case类进行排序,忽略None?

时间:2014-12-19 19:18:21

标签: scala

给定List[Foo] Foo定义为:

case class Foo(bar: Option[String])

我最好的方法是按字母顺序找到第一个Foo的{​​{1}}?

例如,如果我有:

bar

我想返回val l = List(Foo(None), Foo(Some("xyz")), Foo(Some("abc")))

5 个答案:

答案 0 :(得分:2)

您可以使用sortBy,然后使用collectFirst模式匹配不包含None的第一个元素:

l.sortBy(_.bar).collectFirst { case x @ Foo(Some(_)) => x }

请注意,这将返回Option[Foo],如果列表中的所有元素都包含None,则上述代码将返回None。否则Some(first matching element)

如果您非常确信该列表将始终包含非空Option,请在结尾处使用get

答案 1 :(得分:2)

   list.filter(_.bar.isDefined) match {
      case Nil => Foo(None)
      case l => l.minBy(_.bar)
   }

或者,如果总会有至少一个非空选项,那么只需list.filter(_.bar.isDefined).minBy(_.bar)

这比(排序)好于排序,因为它是线性的,并且不需要分配数据结构。

另一种可能性,即甚至(一点点)更有效(但稍微更多地参与)

list.reduceOption { 
    case (Foo(None), x) => x
    case (x, Foo(None)) => x
    case (Foo(Some(x)), Foo(Some(y))) => if ( x < y ) Foo(Some(x)) else Foo(Some(y))
}

答案 2 :(得分:1)

这是我到目前为止看到的最实用的方法。它也不需要对任何东西进行排序:

 case class Foo(bar: Option[String])
 val l = List(Foo(None), Foo(Some("xyz")), Foo(Some("abc")))

  val foo = l.foldLeft(Foo(None)) {
    (acc, elem) => (for {
      elemB  <- elem.bar
      accB <- acc.bar
      smaller = if( elemB <  accB) elem else acc
    } yield smaller)
      .getOrElse(elem)
  }

  System.out.println(foo.bar)

答案 3 :(得分:0)

您也可以使用foldLeft。它将更快地工作,因为不需要对列表进行排序:

import Ordering.Implicits._

val res = l.foldLeft(Foo(None))((res, foo) =>
  if (res.bar.isEmpty) foo
  else if (foo.bar.isEmpty) res
  else if (res.bar < foo.bar) res
  else foo)

println(res) // Foo(Some(abc))

答案 4 :(得分:0)

您可以在排序前过滤列表。

l.filter {_ match {
    case Foo(None) => false
    case _ => true
  }
}.minBy(_.bar)