2011-09-28 13 views
17

Nói rằng tôi có một chức năng để kiểm tra xem một số hoạt động được áp dụng cho một thể hiện của A và nếu như vậy, trả về một thể hiện của B hoặc None:Scala: lọc một tập hợp các tùy chọn

def checker[A,B](a: A) : Option[B] = ... 

Bây giờ tôi muốn để tạo một bộ sưu tập mới chứa tất cả các phiên bản B hợp lệ, hãy bỏ các giá trị None. Đoạn mã sau dường như thực hiện công việc, nhưng chắc chắn có một cách tốt hơn:

val as = List[A](a1, a2, a3, ...) 
    val bs = 
    as 
    .map((a) => checker(a)) // List[A] => List[Option[B]] 
    .filter(_.isDefined)  // List[Option[B]] => List[Option[B]] 
    .map(_.get)    // List[Option[B]] => List[B] 

Cảm ơn!

+28

flatMap shit –

+0

@oxbow_lakes Tôi tin rằng báo giá chính xác là: _ "Đây là gì? Giờ nghiệp dư? FlatMap shit!" _ –

+0

Trích dẫn đó có xuất phát trên twitter không? – huynhjl

Trả lời

25

này nên làm điều đó:

val bs = as.flatMap(checker) 
+0

Không hoạt động vì tôi vì nhiều lý do: 1. suy luận kiểu, 2. Danh sách # flatMap mong đợi một GenTraversableOnce. Đúng là as.flatMap {a => checker [A, B] (a)} – IttayD

+0

Tôi đã thử nghiệm nó với một hàm từ 'Int' đến' Option [String] '. Trường hợp xấu nhất, bạn phải thêm một số loại rõ ràng vào nó. –

+2

hoạt động với tôi trong 2.9.1 –

10

Câu trả lời trên là chính xác, nhưng nếu bạn có thể viết lại checker, tôi đề nghị bạn sử dụng PartialFunctioncollect. PartialFunction là một chức năng của loại A => B mà không cần định nghĩa cho tất cả các giá trị của A. Đây là một ví dụ đơn giản:

scala> List(1, 2, 3, 4, "5") collect {case x : Int => x + 42} 
res1: List[Int] = List(43, 44, 45, 46) 

collect mất một thể hiện của PartialFunction như là đối số và áp dụng nó cho tất cả các yếu tố của bộ sưu tập. Trong trường hợp của chúng tôi, hàm chỉ được xác định cho Ints"5" được lọc. Vì vậy, collect là sự kết hợp của mapfilter, chính xác là trường hợp của bạn.

+1

'collection' thực sự là một sự kết hợp của' filter' và sau đó là 'map', nhưng nó thường không hoạt động theo hướng khác (' map' ** rồi ** 'filter') , vì bạn cần xác định bộ lọc trong phần bảo vệ của câu lệnh case. Vì vậy, nó sẽ là tuyệt vời cho việc thay thế hai câu lệnh cuối cùng của OP (với '.collect {case Some (x) => x}'), nhưng nếu 'checker' liên quan đến bất kỳ loại phép tính không tầm thường nào để quyết định trả về 'Some' hoặc' None', điều này có thể khó viết như một phần chức năng. –