2015-12-16 15 views
7

Hãy tưởng tượng chúng tôi có mã này hoạt động hoàn hảo cho n >= 0.Một cách ngắn gọn để không thực thi vòng lặp bây giờ là C-Style cho các vòng lặp sẽ bị xóa khỏi Swift 3?

func fibonacci(n: Int) -> Int { 
    var memo = [0,1] 
    for var i = 2; i <= n; i++ { 
     memo.append(memo[i-1] + memo[i-2]) 
    } 
    return memo[n] 
} 

Nếu tôi loại bỏ C-phong cách cho vòng lặp due to upcoming changes to Swift 3.0, tôi nhận được một cái gì đó như thế này:

func fibonacci(n: Int) -> Int { 
    var memo = [0,1] 
    for i in 2...n { 
     memo.append(memo[i-1] + memo[i-2]) 
    } 
    return memo[n] 
} 

Trong khi điều này hoạt động tốt cho n >= 2, nó không thành công cho những con số 01 với thông báo lỗi này :

fatal error: Can't form Range with end < start

Cách ngắn gọn nhất để sửa mã này để mã hoạt động chính xác cholà gìvà 1?

(Lưu ý: Không sao đâu, và thậm chí mong muốn, cho số âm sụp đổ các ứng dụng.)


Lưu ý: Tôi nhận ra tôi có thể thêm một tuyên bố bảo vệ:

guard n >= 2 else { return memo[n] }

... nhưng tôi hy vọng có một cách tốt hơn để khắc phục phần lỗi của mã (2...n).

Ví dụ: nếu có cách súc tích để tạo dải ô trả về 0 thành phần nếu end < start, đó sẽ là giải pháp lý tưởng hơn.

+1

Tôi nghĩ rằng giải pháp 'bảo vệ 'sẽ là phù hợp nhất. – zneak

Trả lời

6

Để thực hiện việc này theo cách hoạt động cho n < 2, bạn có thể sử dụng phương pháp stride.

let startIndex = 2 
let endIndex = n 

for i in stride(from: startIndex, through: endIndex, by: 1) { 
    memo.append(memo[i-1] + memo[i-2]) 
} 
+0

Bạn đã đúng! Tôi đã không nghĩ về điều đó. (Có một dấu phẩy bị thiếu giữa các đối số. Bạn cũng có thể viết trực tiếp 'cho i trong 2.stride (thông qua: n, bởi: 1)'.) –

+0

@MartinR Cố định, cảm ơn. Tôi đã sử dụng các hằng số được đặt tên riêng để cố gắng làm cho ví dụ trở nên tự giải thích hơn. –

+0

Cảm ơn! Có cách nào ngắn hơn để làm điều này không? ví dụ. thông qua phần mở rộng hoặc ghi đè ... vv, vì vòng lặp for là khá phổ biến và bước đi khá dài ... – hyouuu

6

Bạn có thể dễ dàng tạo ra một phạm vi hợp lệ với max() chức năng:

for i in 2 ..< max(2, n+1) { 
    memo.append(memo[i-1] + memo[i-2]) 
} 

Đây quả là một loạt trống 2 ..< 2 nếu n < 2.

Điều quan trọng là sử dụng toán tử ..<loại trừ giới hạn trên vì 2 ... 1 không phải là phạm vi hợp lệ.

Nhưng chức năng này, tôi chỉ đơn giản là sẽ đối xử với các trường hợp đặc biệt đầu tiên

func fibonacci(n: Int) -> Int { 
    // Let it crash if n < 0: 
    precondition(n >= 0, "n must not be negative") 

    // Handle n = 0, 1: 
    if n <= 1 { 
     return n 
    } 

    // Handle n >= 2: 
    var memo = [0,1] 
    for i in 2 ... n { 
     memo.append(memo[i-1] + memo[i-2]) 
    } 
    return memo[n] 
} 

(Lưu ý rằng mảng memo của bạn được thiết lập với giá trị ban đầu [0, 1] cho mỗi cuộc gọi chức năng, do đó giá trị không thực sự "memoized " Nếu không có ghi nhớ bạn không cần một mảng, nó sẽ đủ để giữ cho hai số cuối cùng để tính toán tiếp theo.)

2

Khi nó quay ra, biến i sẽ luôn bằng count của việc ghi nhớ mảng, vì vậy bạn chỉ có thể sử dụng như điều kiện vòng lặp của bạn:

func fibonacci(n: Int) -> Int { 
    var memo = [0,1] 
    while n >= memo.count { 
    memo.append(memo[memo.count-1] + memo[memo.count-2]) 
    } 
    return memo[n] 
} 

Ngoài ra, bạn có thể thể hiện vòng lặp là một hàm đệ quy:

func fibonacci(n: Int) -> Int { 
    var memo = [0,1] 
    func rec(i: Int) -> Int { 
    if i >= memo.count { memo.append(rec(i-2) + rec(i-1)) } 
    return memo[i] 
    } 
    return rec(n) 
} 

Thực sự, tuy nhiên, if sự là giải pháp tốt nhất ở đây.Range s không cho phép kết thúc nhỏ hơn đầu bằng thiết kế. Dòng bổ sung cho:

func fibonacci(n: Int) -> Int { 
    if n < 2 { return n } 
    var memo = [0,1] 
    for i in 2...n { 
    memo.append(memo[i-1] + memo[i-2]) 
    } 
    return memo[n] 
} 

Có thể đọc và dễ hiểu. (Theo tôi, mã ở trên tốt hơn phiên bản for ;;)

0

@ câu trả lời của Marc là rất tốt: https://stackoverflow.com/a/34324032/1032900

Nhưng cú pháp sải chân quá dài cho việc sử dụng thường xuyên, vì vậy tôi đã làm cho nó một chút dễ chịu hơn cho phổ biến i ++ tập quán ...

extension Strideable { 
    @warn_unused_result 
    public func stride(to end: Self) -> StrideTo<Self> { 
    return stride(to: end, by: 1) 
    } 
} 

extension Strideable { 
    @warn_unused_result 
    public func stride(thru end: Self) -> StrideThrough<Self> { 
    return stride(through: end, by: 1) 
    } 
} 

Vì vậy, hãy sử dụng như sau:

for i in startPos.stride(to: endPos) { 
    print("pos at: \(i)") 
} 
Các vấn đề liên quan