2014-12-19 23 views

回答

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

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

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

請注意,這將返回Option[Foo],以防列表c中的所有元素保留None,那麼上面的代碼將返回None。否則Some(first matching element)

如果您確信列表總是包含非空的Option,那麼最後使用get

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)) 
0

您可以在排序前篩選器列表。

l.filter {_ match { 
    case Foo(None) => false 
    case _ => true 
    } 
}.minBy(_.bar) 
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)