2015-07-05 17 views
7

Tại sao lazy được sử dụng ở đây?Tính linh hoạt trong Swift

extension SequenceType { 
    func mapSome<U>(transform: Generator.Element -> U?) -> [U] { 
     var result: [U] = [] 
     for case let x? in lazy(self).map(transform) { 
      result.append(x) 
     } 
     return result 
    } 
} 

phần mở rộng này có một chức năng chuyển đổi mà trả về một tùy chọn, và trả về một mảng chỉ những giá trị mà không được biến thành con số không

Tại sao không chỉ cần sử dụng self.map(transform)? là sự lười biếng cần thiết ở đây?

+0

Nhân tiện, 'flatMap (transform: Generator.Element -> U?) -> [U] 'hiện có sẵn trong thư viện chuẩn Swift 2 :) – jtbandes

Trả lời

11

Nó tránh việc tạo mảng trung gian.

self.map(transform) 

trả về một mảng chứa các kết quả của việc chuyển đổi tất cả yếu tố trình tự, mà sau đó sẽ được đi qua để xây dựng kết quả mảng với các yếu tố phi nil.

lazy(self).map(transform) 

là một chuỗi trong những yếu tố biến đổi , mà sau đó lặp qua để có được những yếu tố phi nil. Các phần tử được chuyển đổi được tính toán trong quá trình liệt kê. (Mỗi cuộc gọi đến next() trên trình tự lười biếng tạo ra một phần tử bằng cách chuyển đổi phần tử tiếp theo của chuỗi gốc.)

Cả hai phương pháp đều hoạt động. Phương thức lười biếng có lẽ sẽ thực hiện tốt hơn cho các chuỗi lớn, nhưng có thể phụ thuộc vào nhiều yếu tố (kích thước của mảng, cho dù các phần tử là giá trị hoặc loại tham chiếu, tốn kém như thế nào để sao chép phần tử mảng vv). Đối với các mảng nhỏ , phương thức lười biếng có thể chậm hơn do chi phí bổ sung . Trong một ứng dụng cụ thể, việc lập hồ sơ với các Công cụ sẽ trợ giúp để quyết định nên sử dụng phương pháp nào.

+1

Các thử nghiệm hiệu suất của tôi (cho rằng không chính thức) cho thấy lười biếng và không lười biếng thực hiện giống nhau đối với mảng nhỏ, nhưng lười biếng đó tạo ra một cạnh khiêm tốn lớn hơn những cái, do đó, nó có giá trị bao gồm (đặc biệt là trong một chức năng thư viện như thế này). Điều thú vị là, 'flatMap', tức là 2.0 bây giờ thực hiện cùng một logic, thực hiện tồi tệ hơn cả hai. –

+0

@AirspeedVelocity: Điều đó thật thú vị, cảm ơn bạn đã phản hồi. –

+0

Thật thú vị tôi đã có kết quả ngược lại !? Xem câu trả lời của tôi dưới đây. – Qbyte

5

Vì Martin R đã đề cập lazy() tránh việc tạo mảng trung gian. Tuy nhiên, nếu tôi so sánh thời gian thực hiện của hàm trên các mảng có kích thước khác nhau, bạn thấy rằng lazy() là "chỉ" nhanh hơn 10%.

Thật thú vị, bạn thấy rằng lazy() là dành cho các mảng có ít hơn 200 phần tử nhanh gấp 2 lần và có nhiều phần tử nhanh hơn như hàm không có chuyển đổi (nhanh hơn 10%).

(Tested với Xcode 6.4 và Xcode 7 với chức năng toàn cầu và mở rộng giao thức trong một sân chơi như (biên soạn) file nguồn)

Vì vậy lazy() thà được sử dụng cho Sequences mà bạn không biết nếu nó là hữu hạn . Sau đó, cho vòng có khả năng sử dụng với break hoặc return:

for element in lazy(sequence).map{ ... } { 
    if element == 1000 { 
     break 
    } 
    // use element 
} 

Nếu bạn gọi bản đồ trên một vô hạn Sequence (như 1,2,3 ...) thực hiện cũng sẽ là vô hạn. Với lazy() việc chuyển đổi và việc thực thi bị "trì hoãn", do đó bạn có thể xử lý các chuỗi "lớn" và vô hạn hiệu quả hơn nếu bạn thoát khỏi vòng lặp trước phần tử cuối cùng.

Các vấn đề liên quan