給定List[Foo]
其中Foo
被定義爲:如何使用Option [String]按字母順序排序案例類忽略無?
什麼給我找的Foo
與按字母順序排列的第一bar
的最佳方式?
舉例來說,如果我有:
val l = List(Foo(None), Foo(Some("xyz")), Foo(Some("abc")))
我想回Foo(Some("abc"))
給定List[Foo]
其中Foo
被定義爲:如何使用Option [String]按字母順序排序案例類忽略無?
什麼給我找的Foo
與按字母順序排列的第一bar
的最佳方式?
舉例來說,如果我有:
val l = List(Foo(None), Foo(Some("xyz")), Foo(Some("abc")))
我想回Foo(Some("abc"))
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))
}
您可以使用sortBy
,然後collectFirst
模式匹配不包含None
第一個元素:
l.sortBy(_.bar).collectFirst { case x @ Foo(Some(_)) => x }
請注意,這將返回Option[Foo]
,以防列表c中的所有元素保留None
,那麼上面的代碼將返回None
。否則Some(first matching element)
。
如果您確信列表總是包含非空的Option
,那麼最後使用get
。
您也可以使用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))
您可以在排序前篩選器列表。
l.filter {_ match {
case Foo(None) => false
case _ => true
}
}.minBy(_.bar)
這是迄今爲止我看到的最實用的方法。它也不需要排序:
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)