2010-05-24 42 views
25

使用Scala的2.7.7:如何使用高階函數來平坦化選項列表?

如果我有選擇的名單,我可以用一個換理解它們壓平:

val listOfOptions = List(None, Some("hi"), None) 
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None) 

scala> for (opt <- listOfOptions; string <- opt) yield string 
res0: List[java.lang.String] = List(hi) 

我不喜歡這種風格,而寧願使用HOF。這種嘗試是太冗長是可以接受的:

scala> listOfOptions.flatMap(opt => if (opt.isDefined) Some(opt.get) else None) 
res1: List[java.lang.String] = List(hi) 

憑直覺我本來期望下面的工作,但它並不:

scala> List.flatten(listOfOptions) 
<console>:6: error: type mismatch; 
found : List[Option[java.lang.String]] 
required: List[List[?]] 
     List.flatten(listOfOptions) 

即使下面似乎像它應該工作,但沒有按「T:

scala> listOfOptions.flatMap(_: Option[String]) 
<console>:6: error: type mismatch; 
found : Option[String] 
required: (Option[java.lang.String]) => Iterable[?] 
     listOfOptions.flatMap(_: Option[String]) 
         ^

我能想出的最好的是:

scala> listOfOptions.flatMap(_.toList)   
res2: List[java.lang.String] = List(hi) 

...但我寧願不必將選項轉換爲列表。這似乎笨重。

有什麼建議嗎?

回答

46

在斯卡拉2.8,扁平化將工作:


Welcome to Scala version 2.8.0.RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> val listOfOptions = List(None, Some("hi"), None) 
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None) 

scala> listOfOptions flatten 
res0: List[java.lang.String] = List(hi) 

這不會在2.7.7工作,但是:


Welcome to Scala version 2.7.7.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20). 

scala> val listOfOptions = List(None, Some("hi"), None) 
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None) 

scala> listOfOptions.flatten 
:6: error: no implicit argument matching parameter type (Option[java.lang.String]) => Iterable[Nothing] was found. 
     listOfOptions.flatten 

的集合庫進行了重新設計,並提高了很多在2.8,所以也許你可能想嘗試使用最新的Scala 2.8 RC,看看它是否更容易使用。

如果你真的不想使用toList方法,我想你也可以寫這樣的:


scala> listOfOptions.flatMap(o => o) 
res: List[java.lang.String] = List(hi) 

也不是美的東西也許是,但至少這個工作在2.7。 7。

+3

哦,是的。謝謝!我曾經偶然碰到過flatMap(o => o),但很快就忘了它。爲什麼flatMap(_)不能同樣工作,這是一件奇怪的事情。 – Synesso 2010-05-24 07:03:19

18

爲了補充阿爾揚的回答,在斯卡拉2.7.7,您可以使用List#flatten,但你需要幫助走出型inferencer:

Welcome to Scala version 2.7.7.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> val listOfOptions = List(None, Some("hi"), None) 
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None) 

scala> listOfOptions.flatten[String]     
res0: List[String] = List(hi) 

scala> val x: List[String] = listOfOptions.flatten 
x: List[String] = List(hi)