2010-05-24 31 views
25

Sử dụng Scala 2.7.7:Làm thế nào để làm phẳng danh sách các tùy chọn sử dụng các hàm bậc cao hơn?

Nếu tôi có một danh sách các tùy chọn, tôi có thể san bằng chúng bằng cho-hiểu:

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) 

tôi không thích phong cách này, và thà sử dụng một HOF. Nỗ lực này là quá dài dòng để được chấp nhận:

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

trực giác tôi dự kiến ​​sẽ có sau đây để làm việc, nhưng nó không:

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

Ngay cả sau có vẻ như nó nên làm việc, nhưng doesn 't:

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

Điều tốt nhất tôi có thể đưa ra là:

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

... nhưng tôi sẽ không muốn chuyển đổi tùy chọn thành danh sách. Điều đó có vẻ hơi vụng về.

Bạn có lời khuyên nào không?

Trả lời

46

Trong Scala 2.8, flatten sẽ làm việc:


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) 

này không hoạt động trong 2.7.7, tuy nhiên:


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 

Thư viện các bộ sưu tập đã được thiết kế lại, và đã được cải thiện rất nhiều trong 2.8, vì vậy có lẽ bạn có thể muốn thử sử dụng Scala 2.8 RC mới nhất và xem liệu điều đó có giúp bạn sử dụng dễ dàng hơn không.

Nếu bạn thực sự không muốn sử dụng phương pháp ToList, tôi đoán bạn cũng có thể viết nó như thế này:


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

Cũng không phải là một điều của vẻ đẹp có lẽ, nhưng ít nhất điều này làm việc trong 2,7. 7.

+3

Ồ vâng. Cảm ơn bạn! Tôi đã từng vấp ngã khi flatMap (o => o) nhưng nhanh chóng quên nó đi. Tại sao flatMap (_) không hoạt động như nhau cũng là một điều tò mò. – Synesso

18

Để bổ sung cho câu trả lời Arjan, trong Scala 2.7.7 bạn có thể sử dụng List#flatten, nhưng bạn cần phải giúp đỡ các loại 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) 
Các vấn đề liên quan