Fibonacci numbers generator in Swift 3 - swift

The following Q&A covers a few methods of generating Fibonacci numbers in Swift, but it's quite outdated (Swift 1.2?):
Sum of Fibonacci term using Functional Swift
Question: How could we generate Fibonacci numbers neatly using modern Swift (Swift >= 3)? Preferably methods avoiding explicit recursion.

An alternative for Swift 3.0 would be to use the helper function
public func sequence<T>(first: T, while condition: #escaping (T)-> Bool, next: #escaping (T) -> T) -> UnfoldSequence<T, T> {
let nextState = { (state: inout T) -> T? in
// Return `nil` if condition is no longer satisfied:
guard condition(state) else { return nil }
// Update current value _after_ returning from this call:
defer { state = next(state) }
// Return current value:
return state
}
return sequence(state: first, next: nextState)
}
from Express for loops in swift with dynamic range:
for f in sequence(first: (0, 1), while: { $1 <= 50 }, next: { ($1, $0 + $1)}) {
print(f.1)
}
// 1 1 2 3 5 8 13 21 34
Note that in order to include zero in the resulting sequence, it
suffices to replace the initial value (0, 1) by (1, 0):
for f in sequence(first: (1, 0), while: { $1 <= 50 }, next: { ($1, $0 + $1)}) {
print(f.1)
}
// 0 1 1 2 3 5 8 13 21 34
That makes the "artificial" check
if pair.1 == 0 { pair.1 = 1; return 0 }
redundant. The underlying reason is that the Fibonacci numbers can
be generalized to negative indices (https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers):
... -8, 5, -3, 2, -1, 1, 0, 1, 1, 2, 3, 5, 8, ...

Using the global sequence(state:next:) function
Swift 3.0
As one alternative we could make use of one the neat global sequence functions, a pair of functions that were implemented in Swift 3.0 (as described in evolution proposal SE-0094).
sequence(first:next:)
sequence(state:next:)
Using the latter of these, we may keep the previous and current state of the Fibonacci numbers sequence as the mutable state property in the next closure of sequence(state:next:).
func fibs(through: Int, includingZero useZero: Bool = false)
-> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: useZero ? (1, 0) : (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
guard pair.1 <= through else { return nil }
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
})
}
// explicit type annotation of inout parameter closure
// needed due to (current) limitation in Swift's type
// inference
// alternatively, always start from one: drop useZero
// conditional at 'state' initialization
func fibs1(through: Int)
-> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
guard pair.1 <= through else { return nil }
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
})
}
Or, condensing this using tuple hacks (however executing next one extra, unnecessary, time)
func fibs(through: Int, includingZero useZero: Bool = false) -> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: useZero ? (1, 0) : (0, 1), next: {
($0.1 <= through ? $0.1 : Optional<Int>.none, $0 = ($0.1, $0.0 + $0.1)).0 })
}
func fibs1(through: Int) -> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: (0, 1), next: {
($0.1 <= through ? $0.1 : Optional<Int>.none, $0 = ($0.1, $0.0 + $0.1)).0 })
}
Note that we explicitly terminate the sequences with a nil return when the ... <= through condition is no longer met.
Example usage:
// fib numbers up through 50, excluding 0
fibs(through: 50).forEach { print($0) }
// 1 1 2 3 5 8 13 21 34
// ... or
fibs1(through: 50).forEach { print($0) }
// 1 1 2 3 5 8 13 21 34
// ... including 0
fibs(through: 50, includingZero: true).forEach { print($0) }
// 0 1 1 2 3 5 8 13 21 34
// project Euler #2: sum of even fib numbers up to 4000000
print(fibs(through: 4_000_000)
.reduce(0) { $1 % 2 == 0 ? $0 + $1 : $0 }) // 4 613 732
We could also remove the termination criteria from above to construct an infinite sequence of fibonacci numbers, to be used in combination e.g. with prefix:
func infFibs() -> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: (0, 1), next: {
(pair: inout (Int, Int)) -> Int in (pair.1, pair = (pair.1, pair.0 + pair.1)).0 })
}
// prefix the first 6 fib numbers (excluding 0) from
// the infinite sequence of fib numbers
infFibs().prefix(10).forEach { print($0) }
// 1 1 2 3 5 8 13 21 34 55
Swift 3.1
When Swift 3.1 arrives, the prefix(while:) method for sequences, as described in evolution proposal SE-0045, will have been implemented. Using this additional feature, we can modify the fibs methods above to avoid the explicit by-nil conditional sequence termination:
func fibs(through: Int, startingFromZero useZero: Bool = false)
-> AnySequence<Int> {
return sequence(state: useZero ? (1, 0) : (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
}).prefix(while: { $0 <= through })
}
// alternatively, always start from one: drop useZero
// conditional at 'state' initialization
func fibs1(through: Int) -> AnySequence<Int> {
return sequence(state: (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
}).prefix(while: { $0 <= through })
}
Examples should work the same as for Swift 3.0 above.

In Swift 3.1, here's an iterator that generates Fibonacci numbers forever, and an infinite sequence derived from it:
class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)
func next() -> Int? {
(a, b) = (b, a + b)
return a
}
}
let fibs = AnySequence{FibIterator()}
To print the first 10 Fibonacci numbers:
> print(Array(fibs.prefix(10)))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
If you want to filter or map this infinite sequence you'll need to call .lazy first, since otherwise filter or map will behave strictly and will not terminate. Here are the first 5 even Fibonacci numbers:
> print( Array(fibs.lazy.filter{$0 % 2 == 0}.prefix(5)) )
[2, 8, 34, 144, 610]

I have just saw Dhaval Gevariya code and just move print fibonacci above instead below and now it will print 0 also
func fibonaci(n: Int)
{
var fiboNumberOne = 1
var fiboNumberTwo = 0
for i in 0..<n
{
print("Fibonaci \(fiboNumberTwo)")
let temp = fiboNumberOne + fiboNumberTwo
fiboNumberOne = fiboNumberTwo
fiboNumberTwo = temp
}
}
fibonaci(n: 5)

From David kopec's book “Classic Computer Science Problems in Swift”:
By recursion
var fibMemo: [UInt: UInt] = [0: 0, 1: 1] // our old base cases
func fib3(n: UInt) ­> UInt
{
if let result = fibMemo[n]
{
// our new base case
return result
}
else
{
fibMemo[n] = fib3(n: n ­ 1) + fib3(n: n ­ 2) // memoization
}
return fibMemo[n]!
}
By iterative approach
func fib4(n: UInt) ­> UInt
{
if (n == 0)
{
// special case
return n
}
var last: UInt = 0, next: UInt = 1 // initially set to fib(0) & fib(1
for _ in 1..<n {
(last, next) = (next, last + next) }
return next
}

func fibonaci(n: Int)
{
var fiboNumberOne = 1
var fiboNumberTwo = 0
for i in 0..<n
{
let temp = fiboNumberOne + fiboNumberTwo
fiboNumberOne = fiboNumberTwo
fiboNumberTwo = temp
print("Fibonaci \(fiboNumberTwo)")
}
}
fibonaci(n: 5)

If you don't need accuracy there is O(1) function for your needs:
func fibonacci(iteration: Int) -> Int {
return Int(round(pow(1.618033988749895, Double(iteration)) / 2.23606797749979))
}
So here how it works:
print((0..<40).map(fibonacci))
// prints [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
Works perfectly until 70 iteration.
Warning: On 71 iteration returns 308061521170130 instead of 308061521170129

Details
Xcode 9.3.1, Swift 4.1
Solution
extension Array where Element: BinaryInteger {
private mutating func fibonacci(index: Int) {
if index >= count {
return
}
self[index] = self[index-1] + self[index-2]
return fibonacci(index: index+1)
}
init(fibonacci count: Int) {
self = [Element]()
if count < 0 {
self = [Element]()
}
self = [Element](repeating: 1, count: count)
fibonacci(index: 2)
}
static func calculate(fibonacciAt index: Int) -> Element? {
if index < 0 {
return nil
}
if index < 2 {
return 1
}
func calc(a: Element, b: Element, index: Int) -> Element {
if index == 1 {
return b
}
return calc(a: b, b: a+b, index: index-1)
}
return calc(a: 1, b: 1, index: index)
}
}
Usage
let fibonacciSequence = [Int](fibonacci: 15)
let index = 12
print(fibonacciSequence)
print(fibonacciSequence[index])
let value = [Int].calculate(fibonacciAt: index)
print("\(value!)")
Results

Details
XCode Version 10.0 beta 6, Swift 4.2
The control flow is required to get either the first or the first two iterations of the fibonacci seq starting with 0.
Time Complexity: O(n)
Space Complexity: O(n)
Code
func fib(_ n: Int) -> [Int] {
var fibs: [Int] = [0, 1]
switch n
{
case 1: return [fibs[0]]
case 2: return [fibs[0],fibs[1]]
default:
(2...n-1).forEach
{ i in
fibs.append(fibs[i - 1] + fibs[i - 2])
}
return fibs
}
}
Usage
fib(8)
//print(fib(8))

// MARK: - Function
func fibonacciSeries(_ num1 : Int,_ num2 : Int,_ term : Int,_ termCount : Int) -> Void{
if termCount != term{
print(num1)
fibonacciSeries(num2, num2+num1, term, termCount + 1)
}
}
// MARK: - Calling Of Function
fibonacciSeries(0, 1, 5, 0)
// MARK: - out Put
0 1 1 2 3
Note Need to Change only No Of term for fibonacci Series.

func fibonacci(n: Int) -> Int {
if n <= 1 {
return n
} else {
return fibonacci(n: n - 1) + fibonacci(n: n - 2)
}
}
print(fibonacci(n: 10))

This is bad to use recursion!! recursion is evil!
I would have rather done it this way:
func fibo(_ n:Int) -> Int {
var a = 0
var b = 1
for _ in 0..<n {
a += b
b = a - b
}
return a
}
Which is much faster and cleaner!

Related

Distinct Pair sum swift

Hi am trying to get the number of distinct pair that add up to a particular value. currently I am able to get equal pairs but I am unable to get a work around for distinct pairs.
func checkPairs(in numbers: [Int], forSum target: Int) -> Int {
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
return x
}
if x + y > target {
break
}
}
}
return 0
}
print(checkPairs(in: [5,7,9,13,11,6,6,3,3], forSum: 12))
Sets are great for keeping track of unique things. Since you want (5, 7) and (7, 5) to be counted as the same pair, you can always store them in the same order (lowest value first, for instance). Use a struct to store the pair and make it Hashable so that it can be used with a Set. Then add your pairs to the Set as you find them and get the .count at the end.
struct Pair: Hashable, CustomStringConvertible {
let x: Int
let y: Int
var description: String { "(\(x), \(y))" }
init(_ x: Int, _ y: Int) {
self.x = min(x, y)
self.y = max(x, y)
}
}
func checkPairs(in numbers: [Int], forSum target: Int) -> Int {
var set = Set<Pair>()
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
set.insert(Pair(x, y))
}
}
}
print(set)
return set.count
}
print(checkPairs(in: [5,7,9,13,11,6,6,3,3], forSum: 12))
[(6, 6), (5, 7), (3, 9)]
3

How to print the Fibonacci sequence in Swift Playground using recursion

I am trying to use recursion in Swift to print out the Fibonacci sequence for a number "n" iterations. However, I keep getting the same error.
I have already tried doing it without recursion and was able to do it. However, I am now trying to do in a more complex and "computer scientisty" way by using recursion.
func fibonacciSequence (n: Int) -> [Int] {
// Consumes a number "n", which is the number of iterations to go through with the Fibonacci formula and prints such sequence.
var fibonacciArray = [Int]()
for n in 0 ... n {
if n == 0 {
fibonacciArray.append(0)
}
else if n == 1 {
fibonacciArray.append(1)
}
else {
fibonacciArray.append (fibonacciSequence(n: (n - 1)) +
fibonacciSequence(n: (n-2)))
}
}
return fibonacciArray
I expect to call the function with a number n and for the function to print out the Fibonacci sequence. Example: if n = 5, I expect the console to print 0, 1, 1, 2, 3, 5. The error I get is this: (Cannot convert value of type '[Int]' to expected argument type 'Int').
As pointed out above, the return value is causing an error when summed. A possible way (but not recursive) of fixing the code would be to simply change the else statement:
func fibonacciSequence (n: Int) -> [Int] {
// Consumes a number "n", which is the number of iterations to go through with the Fibonacci formula and prints such sequence.
var fibonacciArray = [Int]()
for n in 0 ... n {
if n == 0 {
fibonacciArray.append(0)
}
else if n == 1 {
fibonacciArray.append(1)
}
else {
fibonacciArray.append (fibonacciArray[n-1] + fibonacciArray[n-2] )
}
}
return fibonacciArray
}
A recursive solution would be the following:
func fibonacciSequence (n: Int, sumOne: Int, sumTwo: Int, counter: Int, start: Bool) {
if start {
print(0)
print(1)
}
if counter == -1 {
print(1)
}
if (counter == n - 2) {
return
}
let sum = sumOne + sumTwo
print(sum)
fibonacciSequence(n: n, sumOne: sumTwo , sumTwo: sum, counter: counter + 1, start: false)
}
fibonacciSequence(n: 8, sumOne: 0, sumTwo: 1, counter: 0, start: true)
There is probably a "nicer" way, but I hope it helps. Cheers.
These is my solution for fabonacci series in swift 5 playground
func fibonacci(n: Int) {
var num1 = 0
var num2 = 1
var nextNum = Int()
let i = 1
var array = [Int]()
array.append(num1)
array.append(num2)
for _ in i...n {
nextNum = num1 + num2
num1 = num2
num2 = nextNum
array.append(num2)
print(array)
}
print("result = \(num2)")
}
print(fibonacci(n: 5))
let fibonacci = sequence(state: (0, 1)) {(state: inout (Int, Int)) -> Int? in
defer { state = (state.1, state.0 + state.1) }
return state.0
}
//limit 10
for number in fibonacci.prefix(10) {
print(number)
}
// MARK: - Function
func fibonacciSeries(_ num1 : Int,_ num2 : Int,_ term : Int,_ termCount : Int) -> Void{
if termCount != term{
print(num1)
fibonacciSeries(num2, num2+num1, term, termCount + 1)
}
}
// MARK: - Calling Of Function fibonacciSeries(0, 1, 5, 0)
// MARK: - out Put 0 1 1 2 3
Note Need to Change only No Of term for fibonacci Series.
func fibonacci(n: Int) {
var seq: [Int] = n == 0 ? [0] : [0, 1]
var curNum = 2
while curNum < n{
seq.append(seq[curNum - 1] + seq[curNum - 2])
curNum += 1 }
print(seq) }
Recursive way of fabonacci -> Solutions
func fibo( n: Int) -> Int {
guard n > 1 else { return n }
return fibo(n: n-1) + fibo(n: n-2)
}

where do i go from here? swift

func step(_ g: Int, _ m: Int, _ n: Int) -> (Int, Int)? {
var z = [m]
var x = m
var y = n
while x < y {
x += 1
z += [x]
}
for i in z {
var k = 2
while k < n {
if i % k != 0 && i != k {
}
k += 1
}
}
print(z)
return (0, 0)
}
print (step(2, 100, 130))
so it currently returns the set of numbers 100-130 in the form of an array. the overall function will do more than what i am asking about but for now i just want to create an array that takes the numbers 100-130, or more specifically the numbers x- y and returns an array of prime. the if i%k part need the help. yes i know it is redundant and elongated but im new at this. that being said try to only use the simple shortcuts.
that being said i would also be ok with examples of ways to make it more efficient but im going to need explanations on some of it because.. well im new. for context assume if only been doing this for 20-30 days (coding in general)
you can do this:
let a = 102
let b = 576 // two numbers you want to check within
/**** This function returns your array of primes ****/
func someFunc(x: Int, y: Int) -> [Int] {
var array = Array(x...y) // This is a quick way to map and create array from a range . /// Array(1...5) . ---> [1,2,3,4,5]
for element in array {
if !isPrime(n: element) { // check if numberis prime in a for loop
array.remove(at: array.index(of: element)!) // remove if it isnt
}
}
return array
}
someFunc(x: a, y: b) //this is how you call this func. someFunc(x: 4, y: 8) ---> [5, 7]
// THis is a supporting function to find a prime number .. pretty straight forward, explanation in source link below.
func isPrime(n: Int) -> Bool {
if n <= 1 {
return false
}
if n <= 3 {
return true
}
var i = 2
while i*i <= n {
if n % i == 0 {
return false
}
i = i + 1
}
return true
}
Source: Check if a number is prime?
Firstly, it's a good idea to separate out logic into functions where possible. E.g. Here's a generic function for calculating if a number is prime (adapted from this answer):
func isPrime<T>(_ n: T) -> Bool where T: BinaryInteger {
guard n > 1 else {
return false
}
guard n > 3 else {
return true
}
var i = T(2)
while (i * i) <= n {
if n % i == 0 {
return false
}
i += 1
}
return true
}
To get the numbers by step, Swift provides the stride function. So your function can simplify to:
func step(_ g: Int, _ m: Int, _ n: Int) -> (Int, Int)? {
let z = stride(from: m, to: n, by: g).filter { isPrime($0) }
print(z)
return (0, 0)
}
To explain, stride will return a Sequence of the numbers that you want to step through, which you can then filter to get only those that return true when passed to the function isPrime.
By the way, your example of print(step(2, 100, 130)) should print nothing, because you'll be checking all the even numbers from 100 to 130, which will obviously be non-prime.
I'd also recommend that you don't use single-letter variable names. g, m, n and z aren't descriptive. You want clarity over brevity so that others can understand your code.
This returns an array of primes between 2 numbers:
extension Int {
func isPrime() -> Bool {
if self <= 3 { return self == 2 || self == 3 }
for i in 2...self/2 {
if self % i == 0 {
return false
}
}
return true
}
}
func getPrimes(from start: Int, to end: Int) -> [Int] {
var primes = [Int]()
let range = start > end ? end...start : start...end
for number in range {
if number.isPrime() { primes.append(number) }
}
return primes
}
In the extension you basically loop through every number in between 2 and selected number/2 to check if its divisible or not and return false if it is, else it will return true.
The getPrimes() basically takes in 2 numbers, if the start number is higher than the end number they switch places (a failsafe). Then you just check if the number is prime or not with help of the extension and append the value to the array if it is prime.
func step(_ steps: Int, _ start: Int, _ end: Int) {
var primes = [Int]()
var number = start
repeat {
if number.isPrime() { primes.append(number) }
number+=steps
} while number <= end
}
Here is another function if you want to take steps in the difference higher than 1

Behaviour of lazy dropLast

I'm trying to figure out the behaviour of dropLast when evaluated lazily (questions in bold):
var iterationCount = 0
let sequence = [1, 1, 1].lazy.flatMap { (element: Int) -> [Int] in
iterationCount += 1
return [element, 2]
}.dropLast()
print(iterationCount) // 18
_ = sequence.forEach{_ in}
print(iterationCount) // 30
Shouldn't the first call to print show 0 and the second call to print show 3 since it's lazy? It shows 18 and 30EXAMPLE.
var iterationCount = 0
let sequence = [1, 1, 1].lazy.flatMap { (element: Int) -> [Int] in
iterationCount += 1
return [element, 2]
}
print(iterationCount) // 0
_ = sequence.forEach{_ in}
print(iterationCount) // 3
When I remove the call to dropLast it works as expectedEXAMPLE. Is dropLast the culprit here?
var iterationCount = 0
let sequence = [1, 1, 1].lazy.map { (element: Int) -> [Int] in
iterationCount += 1
return [element, 2]
}.dropLast()
print(iterationCount) // 0
_ = sequence.forEach{_ in}
print(iterationCount) // 2
But wait, there is more. With map, dropLast works as expectedEXAMPLE.
Why is this?

Sum of Fibonacci term using Functional Swift

I'm trying to learn functional Swift and started doing some exercises from Project Euler.
Even Fibonacci numbers
Problem 2
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Implemented a memoized Fibonacci function, as per WWDC advanced Swift videos:
func memoize<T:Hashable, U>( body: ((T)->U,T) -> U) -> (T)->U {
var memo = [T:U]()
var result: ((T)->U)!
result = { x in
if let q = memo[x] { return q }
let r = body(result,x)
memo[x] = r
return r
}
return result
}
let fibonacci = memoize { (fibonacci:Int->Double,n:Int) in n < 2 ? Double(n) : fibonacci(n-1) + fibonacci(n-2) }
and implemented a class that conforms to the Sequence protocol
class FibonacciSequence: SequenceType {
func generate() -> GeneratorOf<Double> {
var n = 0
return GeneratorOf<Double> { fibonacci(n++) }
}
subscript(n: Int) -> Double {
return fibonacci(n)
}
}
The first (non-functional) solution of the problem:
var fib = FibonacciSequence().generate()
var n:Double = 0
var sum:Double = 0
while n < Double(4_000_000) {
if n % 2 == 0 {
sum += n
}
n = fib.next()!
}
println(sum)
The second, more functional solution, using ExSwift for it's takeWhile function
let f = FibonacciSequence()
println((1...40).map { f[$0] }
.filter { $0 % 2 == 0 }
.takeWhile { $0 < 4_000_000 }
.reduce(0, combine: +))
I'd like to improve on this solution, because of the 1...40 range at the begging that's calculating too many terms for no reason. Ideally I'd like to be able to have some sort of infinite range, but at the same time only calculate the required terms that satisfy the condition in the takeWhile
Any suggestions ?
Here I generate the sequence that already stops once max value is reached.
Then you just need to reduce without filtering, just sum 0 when n is odd.
func fibonacciTo(max: Int) -> SequenceOf<Int> {
return SequenceOf { _ -> GeneratorOf<Int> in
var (a, b) = (1, 0)
return GeneratorOf {
(b, a) = (a, b + a)
if b > max { return nil }
return b
}
}
}
let sum = reduce(fibonacciTo(4_000_000), 0) {a, n in (n % 2 == 0) ? a + n : a }
As an alternative, if you wish to keep fibonacci a more general function you could extend SequenceOf with takeWhile and reduce1 obtaining something that resembles function composition:
extension SequenceOf {
func takeWhile(p: (T) -> Bool) -> SequenceOf<T> {
return SequenceOf { _ -> GeneratorOf<T> in
var generator = self.generate()
return GeneratorOf {
if let next = generator.next() {
return p(next) ? next : nil
}
return nil
}
}
}
// Reduce1 since name collision is not resolved
func reduce1<U>(initial: U, combine: (U, T) -> U) -> U {
return reduce(self, initial, combine)
}
}
func fibonacci() -> SequenceOf<Int> {
return SequenceOf { _ -> GeneratorOf<Int> in
var (a, b) = (1, 0)
return GeneratorOf {
(b, a) = (a, b + a)
return b
}
}
}
let sum2 = fibonacci()
.takeWhile({ $0 < 4_000_000 })
.reduce1(0) { a, n in (n % 2 == 0) ? a + n : a}
Hope this helps
There is a filter() function which takes a sequence as an argument:
func filter<S : SequenceType>(source: S, includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element]
but since the return value is an array, this is not suited if you want
to work with an "infinite" sequence. But with
lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 })
you get an "infinite" sequence of the even Fibonacci numbers. You cannot
call the .takeWhile() method of ExSwift on that sequence because
.takeWhile() is only defined for struct SequenceOf and not for
general sequences. But
TakeWhileSequence(
lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),
{ $0 < 4_000_000 }
)
works and gives the sequence of all even Fibonacci numbers less than
4,000,000. Then
let sum = reduce(TakeWhileSequence(
lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),
{ $0 < 4_000_000 }), 0, +)
gives the intended result and computes only the "necessary"
Fibonacci numbers.
Note that there is no actual need to memoize the Fibonacci numbers
here because they are accessed sequentially. Also (as #Matteo
already noticed), all Fibonacci numbers are integers. So you could
define the sequence more simply as
struct FibonacciSequence : SequenceType {
func generate() -> GeneratorOf<Int> {
var current = 1
var next = 1
return GeneratorOf<Int>() {
let result = current
current = next
next += result
return result
};
}
}
and the above computation does still work.
You can get quite close to what you want by using Swift's lazy sequences. If you take your generator of fibonacci numbers (here's the one I'm using:)
var (a, b) = (1, 0)
var fibs = GeneratorOf<Int> {
(b, a) = (a, b + a)
return b
}
You can wrap it in lazy():
var (a, b) = (1, 0)
var fibs = lazy(
GeneratorOf<Int> {
(b, a) = (a, b + a)
return b
}
)
Which exposes it to filter() as a lazy function. This filter() returns:
LazySequence<FilterSequenceView<GeneratorOf<Int>>>
Now, to get your takeWhile() function, you'd need to extend LazySequence:
extension LazySequence {
func takeWhile(condition: S.Generator.Element -> Bool)
-> LazySequence<GeneratorOf<S.Generator.Element>> {
var gen = self.generate()
return lazy( GeneratorOf{ gen.next().flatMap{ condition($0) ? $0 : nil }})
}
}
So that it returns nil (stops the generator) if either the underlying sequence ends, or the condition isn't satisfied.
With all of that, your fibonacci sequence under a given number looks a lot like what you wanted:
fibs
.filter {$0 % 2 == 0}
.takeWhile {$0 < 100}
//2, 8, 34
But, because reduce isn't a method on LazySequence, you have to convert to an array:
fibs
.filter {$0 % 2 == 0}
.takeWhile {$0 < 100}.array
.reduce(0, combine: +)
//44
You could do a quick and dirty extension to LazySequence to get reduce():
extension LazySequence {
func reduce<U>(initial: U, combine: (U, S.Generator.Element) -> U) -> U {
var accu = initial
for element in self { accu = combine(accu, element) }
return accu
}
}
And you can write the final thing like this:
fibs
.filter {$0 % 2 == 0}
.takeWhile {$0 < 100}
.reduce(0, combine: +)
//44
All of those sequences get to persist in their laziness - fibs is infinite, so they wouldn't really work otherwise. In fact, nothing is calculated until reduce: it's all thunks until then.
In Swift 3.1, here's an iterator that generates Fibonacci numbers forever, and an infinite sequence derived from it:
class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)
func next() -> Int? {
(a, b) = (b, a + b)
return a
}
}
let fibs = AnySequence{FibIterator()}
You can get the sum of the even-numbered terms under four million like this:
fibs.prefix{$0 < 4000000}.filter{$0 % 2 == 0}.reduce(0){$0 + $1}
Be warned that filter and map are strict by default, and will run forever on an infinite Sequence. In the example above, this doesn't matter since prefix returns only a finite number of values. You can call .lazy to get a lazy Sequence where filter and map will behave non-strictly. For example, here are the first 5 even Fibonacci numbers:
> print( Array(fibs.lazy.filter{$0 % 2 == 0}.prefix(5)) )
[2, 8, 34, 144, 610]