Sequence Hacking In Swift (II): Extending Sequences - Digital Leaves
post-template-default,single,single-post,postid-1981,single-format-standard,ajax_fade,page_not_loaded,,select-theme-ver-3.8,wpb-js-composer js-comp-ver-5.1.1,vc_responsive

Sequence Hacking In Swift (II): Extending Sequences

Hello, this is the second episode in the “Sequence Hacking in Swift” series. In the previous episode, we learned about sequences, and reviewed the basic operations you can use to make pretty awesome one-line operations. This time, we are going to learn how sequences work to extend them. Why? Because that will allow us to include some pretty cool additions into our swift repertoire to make our daily job faster and easier.

I personally have a big collection of sequence extensions that makes me a happier developer and allows me to be more productive and focus in solving the problem at hand instead of working with structures. Let’s start!

Inside the Sequence

The Sequence is the most basic expression in Swift to represent a group of elements sequentially distributed. The Sequence protocol is defined as follows:

Notice how a Sequence is nothing more than an iterator (compliant with the IteratorProtocol protocol) and a makeIterator() method that returns that iterator. The IteratorProtocol is also very simple:

So basically a Sequence is an iterator that allows us to iterate through a series of elements of type “Iterator.Element” by means of the “next” method, until eventually reaching the end, after which next() will return nil. This is a graphical representation of such an structure:


“Iterator.Element” is a generic abstraction for “The type of element that the iterator might contain, whatever it is”. This Iterator.Element, given the strongly typed nature of Swift, enforces that all elements of the Sequence are of the same type. You use this Iterator.Element to refer to the element type the Sequence contains in a generic way.

Notice also how some methods like “map” use generics too to identify the resulting operations. In this case, we have this syntax:

This means “map is a function that is defined for a type T so that, given a Sequence of elements of type Iterator.Element, will return an array of elements of type “T”, whatever this type is. This generic definitions are used to apply the “map” function to any possible type. For instance, in the sample project of the previous episode, you will recall that we had a map in place to return the names of the Person instance contained in our array:

In this map, “T” is “String”, so we are applying this:

But we also had  an age property (of type Int) in our Person instances, so that would be:

Resulting in us applying this:

To know more about generics, visit Apple’s Swift documentation here. We need to make use of this generic approach for extending Sequence. Concretely, we need to use the Iterator.Element type to perform generic operations on the elements of the sequence.

Extending Sequences

Now it’s time to start extending our sequences! Let’s start by a simple extension to get the unique elements of a sequence. If you recall from the previous episode, we already defined an extension to do that using “reduce” (as we are extending a Sequence, we can happily use all its functions and methods):

Here, we impose a restriction to the types of sequences that will be able to apply the unique() method, and we do that by limiting our Iterator.Element to those that implement the Equatable protocol. As the Apple documentation states, this protocol can be used to check the “contains” value of an element in a collection of elements:

Some sequence and collection operations can be used more simply when the elements conform to Equatable. For example, to check whether an array contains a particular value, you can pass the value itself to the contains(_:) method when the array’s element conforms to Equatable instead of providing a closure that determines equivalence.

Notice also how the returning type of this method will be an array of Iterator.Element. This indicates that we are not changing the type of the elements in the output, we are just removing some of them. Don’t worry if this seems confusing at first, once you get used to think of “Iterator.Element” as the element contained in a Sequence, you’ll get used to work with it.

Thus, these restrictions allow us to set specific functions for sequences whose elements’ type comply with some common protocol

When extending a Sequence, we can make use of any resources we might need, and build extensions that are as complex as necessary. Let’s see another example. This time, we want to be able to get the elements of a Sequence that are duplicated (i.e: those that appear more than once). We will make use of two functions in a Sequence extension. One, called getFrequenciesForSequenceElements, will return a dictionary containing the number of times each element appears in the sequence. Another one, called getFrequencyForSequenceElement, will obtain the frequency for that concrete element (meaning, the number of times an element appears in a sequence). This will allow us to make use of the filter function to filter out those whose frequency is less than 2:

As you may see, we made use of a Dictionary inside our getFrequenciesForSequenceElements method, and why not? We now have a ready to use function to get the number of appearances of any element inside any given sequence.

The last example will illustrate how you can use the iterator inside the Sequence to perform operations that need to access all the elements sequentially. Here, we will build a function to get a random subsequence from any given sequence, containing a random selection of elements of the original sequence. We’ll do this by iterating over the elements via the iterator (retrieved thanks to the makeIterator() method) and checking a random value to determine if the element is included in the resulting sequence or not:

Where to go from here

That’s all for now! In this article, we learned about the inner structure of Sequence in Swift, and how we can add new functionality to all sequences (and, thus, all Collections, Arrays, Sets, etc…) via custom extensions. In the next episode of this series, we will learn how to build our own custom Sequence subclasses, to make powerful, expressive structures with an iterative, predictive behavior. Thanks for taking the time to read this. Have something to add? Don’t hesitate to do so in the comments below!

No Comments

Post a Comment

Before you continue...

Hi there! I created the Digital Tips List, the newsletter for Swift and iOS developers, to share my knowledge with you.

It features exclusive weekly tutorials on Swift and iOS development, Swift code snippets and the Digital Tip of the week.

Besides, If you join the list you'll receive the eBook: "Your First iOS App", that will teach you how to build your first iOS App in less than an hour with no prior Swift or iOS knowledge.

I hate spam, and I promise I'll keep your email address safe.