Imagine we have this code which works perfectly for n >= 0
.
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]
}
If I remove the C-style for loop due to upcoming changes to Swift 3.0, I get something like this:
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]
}
While this works fine for n >= 2
, it fails for the numbers 0
and 1
with this error message:
fatal error: Can't form Range with end < start
What's the most concise way to fix this code so it works properly for 0
and 1
?
(Note: It's okay, and even desirable, for negative numbers to crash the app.)
Note: I realize I could add a guard statement:
guard n >= 2 else { return memo[n] }
... but I'm hoping there is a better way to fix just the faulty part of the code (2...n
).
For example, if there was a concise way to create a range that returns zero elements if end < start
, that would be a more ideal solution.
To do this in a way that works for n < 2, you can use the
stride
method.As it turns out, the variable
i
will always be equal to thecount
of the memoizing array, so you can just use that as your loop condition:Alternatively, you could express the loop as a recursive function:
Really, though,
if
is the best solution here.Range
s don't allow the end to be smaller than the beginning by design. The extra line for:Is readable and understandable. (To my eye, the code above is better than the
for ;;
version)@Marc's answer is great: https://stackoverflow.com/a/34324032/1032900
But the stride syntax is too long for frequent usage, so I made it a little more pleasant for the common i++ usages...
So use like this:
You can easily create a valid range with the
max()
function:This evaluates to an empty range
2 ..< 2
ifn < 2
.It is important to use the
..<
operator which excludes the upper bound because2 ... 1
is not a valid range.But in this function I would simply treat the special cases first
(Note that your
memo
array is set to the initial value[0, 1]
for each function call, so the values are not really "memoized". Without memoization you don't need an array, it would suffice to keep the last two numbers to compute the next.)