Subscribe to my newsletter and never miss the upcoming articles

Using Sequence Function to Solve Math Problem in Swift

Hallo dames en heren, Leo hier. Today we’ll study how to use the Sequence Function to Solve a Math Problem in Swift.

I was watching a youtube video about Math and something come to my mind. The video’s title was “7 is a weird number“, which caught my attention. First, because I like Math, and second because why would a number be weird?

If you want to know just check the video. I strongly recommend the Numberphile channel, they have fantastic content if you like Math.

In the video, he explains a trick to discover if a number is divisible by seven, even with big numbers. And the way the trick works looks like a really interesting function that returns a sequence out of anything.

No more talking, let’s code! But first…  

 

Painting of The Day

The painting I chose today is called The Shop Girl, an 1883 painting by the master James Tissot

Jacques Joseph Tissot, who lived from 15 October 1836 to 8 August 1902, Anglicized as James Tissot, was a French painter and illustrator. Was a well-recognized painter of Paris society before moving to London in late of the 19 century. He became prestigious as a genre painter of well-dressed women shown in various scenes of daily life. He also painted scenes and characters from the Bible.

I chose this painting because she is carrying a package, and when you receive a gift like that you need to unfold it to see what is inside the box. Since we are talking about UnfoldSequences that is curious, right?

 

The Problem – Sequence Function in Swift

You want to know if a number is divisible by seven.

The long story short, you could do something like this to solve our problem today: 

number % 7 == 0 ? print("Is divisible!") : print("Not Divisible!")

But that would be too easy, right? Where’s the fun?

As I was commenting earlier in the Numberphile video Dr. James Grime explains a cool trick to know if a big number is divisible by seven. This involves you mutating the original number until it becomes small enough to discover by yourself if is divisible by seven or not.

Below check the algorithm proposed in the video with the number 434 as an example:

  1. Divide the number by 10 splitting it into two parts. For example, the number 434 would be split into 43 and 4. In this case, 43 is the quotient and 4 is the reminder.
  2. Pick the reminder and multiply by 5, resulting in 20. 
  3. Add that number to the quotient, which would lead us to 43(quotient) + 20( reminder times 5) which is equal to 63.
  4. When the number is less than 100 you can already guess because it is just the multiple of 7 until 14.

And you can reproduce that algorithm with just one Swift function that creates UnfoldSequences for you. The function sequence is part of the Swift Standard Library more specifically in the collections library and it enables you to create a sequence out of any object in Swift.

This is very handy when you don’t want to create a whole type that conforms to Sequence and create your own IteratorProtocol conformance. Needless to say, if you are using this logic throughout the code, probably is better you encapsulate that in a proper type.

Let’s explore this sequence generator function.

 

Exploring the Sequence Function

Let’s start checking how the sequence function is declared and dive in all its parts. 

func sequence<T, State>(
    state: State,
    next: @escaping (inout State) -> T?
) -> UnfoldSequence<T, State>

This is the function that we will be using in this article to implement the algorithm described in the Numberphile video.
The docs state:

Function returns a sequence formed from repeated lazy applications of  next to a mutable state.

Next in this case is an escaping closure which means if you mutate the state inside the closure it will also mutate the state outside the closure.

Also, this function definition is exactly what we need to build our Numberphile algorithm because the algorithm takes the output of the previous computations as an input for the next ones, which looks like a lot with recursive functions, but recursion is not the exercise today.

And the last part is the return of this function which is the UnfoldSequence object. This object is a Sequence whose elements are produced via repeated applications of closure to some mutable state, that is our result. This special kind of sequence has some perks, let’s check them:

  • All the elements of the Sequence are lazily computated, this means that in the time you create the sequence you don’t know how many elements it will contain, that is the unfolding part.
  • It can be potentially infinite, because if the closure never returns nil it will never stop running.
  • You can create UnfoldSequences using two functions: sequence(first:next:)and sequence(state:next:).

 

Now you know the sequence function that generates sequences for you, let’s implement that to solve the Numberphile problem.

 

Code Implementation – Sequence Function to Solve a Math Problem in Swift

We will implement the sequence and use it in a “for each” to check the final result with the Numberphile algorithm constraints explained above.

Check the code below:

var number = 43400

var numberSequence = sequence(state: number) { state -> Int? in
    guard state > 100 else { return nil } // MARK 1
    
    var division = state.quotientAndRemainder(dividingBy: 10) // MARK 2
    let newState = division.remainder * 5 + division.quotient // MARK 3
    
    state = newState // MARK 4
    return state
}

numberSequence.forEach { number in
    print("result 1 -> ", number)
    
    if number < 100 {// MARK 5
        if number % 7 == 0 { // MARk 6
            print("Is Divisible!")
        } else {
            print("Not Divisible!")
        }
    }
}

Explaining all of the MARK comments: 

  1. Mark 1 – The first one is a necessary escape clause for the sequence, otherwise, it would be infinite. How you build sequence functions is much like how you build recursive functions, one of the first things is to think in the escape clause to avoid infinite recursion.
  2. Mark 2 – We are using a useful function that returns an object that has the remainder and the quotient of the division. And this is the first part of the Numberphile trick.
  3. Mark 3 – This is where we implement the second part of the Numberphile trick, where we do 5 times the remainder plus the quotient to generate a new state.
  4. Mark 4 – Here we change the current state to the new state, and return that as the result of this iteration. See that the return and the state could be different. You could have a state that is an Int and the return that is a “Bool?”.
  5. Mark 5 – We are checking if the current returned state is smaller than 100, because of the Numberphile algorithms constraints that say we can only evaluate numbers below 100.
  6. Mark 6 – We are finally doing our final evaluation on the number, and checking if is divisible by 7.

 

The final result of this algorithm is: 

In Mark 4, I explained that the return object of the function can be different than the state object.

The same algorithm could be achieved using different objects in the example below the state will be an Int and the return of each iteration will be an “Bool?”, check the code below: 

var number = 434000

var numberSequence = sequence(state: number) { state -> Bool? in
    guard state > 100 else { return nil }

    var division = state.quotientAndRemainder(dividingBy: 10)
    let newState = division.remainder * 5 + division.quotient

    state = newState

    if newState < 100 {
        if newState % 7 == 0 {
            return true
        }
    }

    return false
}

numberSequence.forEach { result in
    print("result 1 -> ", result)

    if result {
        print("Is Divisible!")
    }
}

Resulting in: 

So depending on that is your goal, you can return anything from each iteration and that doesn’t necessarily have to be the mutating state that you are passing around.

And the algorithm is done!

 

Curiosities on Sequences

If you ever traverse the sequence, in another word, use the next() function until the end, you cannot return to the starting point. And that is different than traversing using “for _ in” or “for each” structures.

Check the examples below: 

var number = 434

//[...]

numberSequence.forEach { number in print("result 1 ->",number) } for number in numberSequence { print("result 2 ->", number) }

The result of the above code is:  

result 1  -> 63

result 2 -> 63

However, if you use the .next() operator in the sequence, you cannot reach the values anymore. And you will understand why in a bit, first check the code below: 

while true {
    let next = numberSequence.next()

    if next == nil {
        break
    }

    print("result with next 1 -> \(next!)")
}

for number in numberSequence {
    print("result 2 ->",number) // doesn't print anything
}

Resulting only in: 

result with next 1 -> 63

But why? If you check the next() signature you will understand why.

mutating func next() -> Element?

That function is mutating which means that if you call it on the numberSequence variable you will mutate it forever. You cannot retrieve elements of it anymore.

And now you might be thinking, but why does the for and forEach or “for _ in” don’t do that?

As the docs states

Whenever you use a `for`-`in` loop with an array, set, or any other collection or sequence, you’re using that type’s iterator. Swift uses a sequence’s or collection’s iterator internally to enable the `for`-`in` loop language construct.

In other words, every time you use an iteration in Swift you are using a copy of the iterator of that Sequence. This way you don’t mess with the sequence itself, but with the copying of the iterator of that Sequence. And that is why if you call the .next() yourself it will change the sequence forever but using Swift embedded for loops doesn’t.

Cool, right?

 

Continue Studying

Studying pure Swift language functions is something that doesn’t come with immediate results. It is something that builds up with time and effort. After reading about the sequence API I would recommend reading the difference between class func and static func in this article. Knowing that can be crucial when you make new APIs and hierarchies for your apps.

When I started learning iOS development I fall in love with the GCD and all its perks, one of the favorite things there is the dispatch groups and I explain exactly how to implement DispatchGroups in Swift in this article. You will learn how to synchronize the response of various API calls in one single point for your apps.

 

Summary – Sequence Function to Solve a Math Problem in Swift

Today we explored an interesting API that allows you to create sequences that are lazily executed as you traverse them. You also implemented a cool Math trick using that sequence function. And finally, we solved using two different approaches for the same problem.

We also studied the difference between using the “next()” function directly in the sequence or using “for _ in” or “forEach” to traverse them, and why you have to be careful with the former.

Fellow developers, that’s all. I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or just leave a comment saying hello. You can also sponsor posts! You can reach me on LinkedIn, or Twitter or send me an e-mail through the contact page.

Thanks for the reading and… That’s all folks.

Image Credit: Wikiart

Share this post:

Related posts

Sponsor