Sequence

A Sequence is a collection of values of the same type and provides the ability to iterate over these values

The most common way to iterate over a Sequence is by for-in, and provides the ability to iterate over these values

for element in someSequence {

doSomething(with: element)

}

We often use for-in loops in data structures such as Array, Dictonary, and set because they implement the Sequence protocol.

Sequence protocol definition:

protocol Sequence{

associatedtype Iterator:IteratorProtocol

func makeIterator()->Iterator

}

The only method of the Sequence protocol that must be implemented is makeIterator(),

MakeIterator () needs to return an Iterator, which is an IteratorProtocol type.

If you provide an Iterator to implement a Sequence, what is an Iterator?

Iterator

Iterator is the IteratorProtocol in the Swift 3.1 standard library. It is used to provide iteration capability for Sequence. For Sequence, we can use for-in to iterate over the elements, but behind the for-in is the IteratorProtocol.

The IteratorProtocol is defined as follows:

public protocol IteratorProtocol{

associatedtype Element

public mutating func next()->Self.Element?

}

Associatedtype declares the type of the element

Next () is used to return the next element in a Sequence, or nil if there is no next element

Examples of Iterator implementation

For example 1

struct SimplestIterator:IteratorProtocol {

typealias Element = Int

mutating func next() -> Int? {

return nil

}

}

The Iterator in this example does not iterate over any elements; rather, the Iterator only calls next() once during iteration.

For example 2

struct ConstantIterator:IteratorProtocol {

typealias Element = Int

mutating func next() -> Int? {

return 1

}

}

This one keeps iterating out 1

Implement a Sequence

Implementing a Sequence starts with implementing an Iterator

Implement an Iterator that takes an array of strings and iterates over the first letter of all the strings in the array. When the last string in the array is iterated over, the iteration is complete and the iteration exits

struct FirstLetterIterator:IteratorProtocol {

typealias Element = String

let stringArr:[String]

var offset:Int

init(strings:[String]) {

stringArr = strings

offset = 0

}

mutating func next() -> String? {

guard offset < stringArr.endIndex else {

return nil

}

let string = stringArr[offset]

offset += 1

return string.substring(to: string.index(string.startIndex, offsetBy: 1))

}

}

Where in next() does the Iterator input an array of strings, judge the bounds, and return the first letter of the string offset, incrementing offset by one

Once you have an implemented Iterator, you can simply implement the Sequence using it and return the Iterator in makeIterator()

struct FirstLetterSequence:Sequence {

let strngs:[String]

func makeIterator() -> FirstLetterIterator {

return FirstLetterIterator(strings:strngs)

}

}

Now that the Sequence implementation is complete,

for letter in FirstLetterSequence(strngs:[“apple”,”banana”,”orange”]) {

print(letter)

}

Print result:

a

b

o

Value type Iterator and reference type Iterator

Value type Iterator

Iterators are generally of value types. A value type Iterator means: When you assign an Iterator to a new variable, you assign the Iterator a copy of all of the Iterator’s states to the new variable. The Iterator continues iterating without affecting the new Iterator.

For example, use the Stride function to create a simple Sequence that starts at 0 and ends at 9, incrementing each time by 1, i.e. [0, 1, 2… 8, 9].

We then get its Iterator and call next() to iterate.

let seq = stride(from: 0, to: 10, by: 1)

var i1 = seq.makeIterator()

print(i1.next())

print(i1.next())

The output

Optional(0)

Optional(1)

And then I do an assignment, and I create a new i2

var i2= i1

Then the output

print(i1.next())

print(i1.next())

print(i2.next())

print(i2.next())

The output

Optional(0)

Optional(1)

Optional(0)

Optional(1)

Here i1 and i2 do not affect each other, assignment makes a complete copy of i1, where the Iterator is an Iterator of value type

An Iterator of the application type

An AnyIterator package can be used to form a reference type Iterator.

var i3 = AnyIterator(i1)

var i4 = i3

The output

print(i3.next())

print(i4.next())

print(i3.next())

print(i4.next())

The output

Optional(0)

Optional(1)

Optional(2)

Optional(3)

An Iterator that refers to a type and is assigned to a new variable affects each other as the new Iterator iterates through the Iterator.

Study blog Reference

Sequence (1) in Swift

Swift Sequence (2)