Swift Standard Libraries: Sequence and Collection Functions

In the last post in this series, I took at look at the protocols that Swift uses to define generators, sequences and collections. In this post I am going to present examples of using the Standard Library Functions that operate on these types. I’ll run through them in alphabetical order.

Throughout this post I will use “a {swift}SequenceType{/swift}” as a shorthand for “an object conforming to {swift}SequenceType{/swift} protocol” and similar shorthand for other type-like protocols.

I have purposely left out the function definitions. Click on the swifter links to see the gory details. In the playground for the post you can also option-click.

So without further ado let’s get going.

advance

Advances an index by a given number of elements.

let data = [2.0,4.0,4.0,4.0,5.0,5.0,7.0,9.0]
var seventh = advance(data.startIndex, 6)
data[seventh]

advance reference on Swifter

contains

Determines if a {swift}SequenceType{/swift} contains an element

// let data = [2.0,4.0,4.0,4.0,5.0,5.0,7.0,9.0]
contains(data, 7.0) // true

or contains an element that satisfies a predicate

// let data = [2.0,4.0,4.0,4.0,5.0,5.0,7.0,9.0]
let doesContain = contains(data) { x in x > 8.0 }
doesContain // true

contains reference on Swifter

count

Counts the number of elements in a range

// let data = [2.0,4.0,4.0,4.0,5.0,5.0,7.0,9.0]
count(data.startIndex..<data.endIndex) // 8
&#91;/swift&#93;
<a href="http://swifter.natecook.com/func/count"><code>count</code> reference on Swifter</a>
<h2>countElements</h2>
Counts the number of elements in a {swift}CollectionType{/swift}
[swift]
// let data = [2.0,4.0,4.0,4.0,5.0,5.0,7.0,9.0]
countElements(data) // 8

countElements reference on Swifter

distance

The distance in elements between two {swift}ForwardIndexTypes{/swift}

// let data = [2.0,4.0,4.0,4.0,5.0,5.0,7.0,9.0]
distance(data.startIndex, data.endIndex) // 8

distance reference on Swifter

dropFirst

Returns the slice obtained by dropping the first element of a sequence

var oneTwoThree = [1,2,3]
dropFirst(oneTwoThree)

dropFirst reference on Swifter

dropLast

Returns the slice obtained by dropping the first element of a sequence

// var oneTwoThree = [1,2,3]
dropFirst(oneTwoThree)

dropLast reference on Swifter

enumerate

// var oneTwoThree = [1,2,3]
println("enumerate")
for (pos,value) in enumerate(oneTwoThree) {
    println("\(pos): \(value)")
}

Prints
[default]
0: 1
1: 2
2: 3
[/default]
enumerate reference on Swifter

equal

Tests two sequences for equality

// var oneTwoThree = [1,2,3]
let fourFive = [4,5]
equal(oneTwoThree, fourFive)

equal reference on Swifter

extend

Extends a mutable sequence

// var oneTwoThree = [1,2,3]
extend(&oneTwoThree, fourFive)
oneTwoThree // after [1,2,3,4,5]

extend reference on Swifter

filter

Filters a sequence based on a predicate

oneTwoThree  // before [1,2,3,4,5] from previous section
oneTwoThree = filter(oneTwoThree) { x in x <= 3 }
oneTwoThree  // after &#91;1,2,3&#93; 
&#91;/swift&#93;
<a href="http://swifter.natecook.com/func/filter"><code>filter</code> reference on Swifter</a>
<h2>first</h2>
Returns the first element of a collection
[swift]
// var oneTwoThree = [1,2,3]
first(oneTwoThree) // {Some 1}
var e = [Int]()
first(e) // nil

first reference on Swifter

indices

Returns the range of valid indices for a collection

// var oneTwoThree = [1,2,3]
indices(oneTwoThree)

indices reference on Swifter

insert

Inserts a new element into a {swift}RangeReplaceableCollectionType{/swift}

// var oneTwoThree = [1,2,3]
var zeroOneTwoThree = oneTwoThree
insert(&zeroOneTwoThree, 0, atIndex:0)

insert reference on Swifter

isEmpty

Returns true if a collection contains no elements

// var zeroOneTwoThree = oneTwoThree
isEmpty("") // true
isEmpty([Int]()) // true
isEmpty(zeroOneTwoThree) // false

isEmpty reference on Swifter

join

Returns a collection formed by placing a separator between each element of a sequence

let relativePathComponents = [ "~", "src", "IDZAQAudioPlayer" ]
join("/", relativePathComponents)

join reference on Swifter

last

Returns the last element of a collection (with a BidirectionalIndexType) or nil

// var oneTwoThree = [1,2,3]
last(oneTwoThree) // 3

last reference on Swifter

lazy

Will be handled in a future post

map

Returns the array generated by applying a function to each element of an array

// var zeroOneTwoThree = [0,1,2,3]
var mapResult = map(zeroOneTwoThree) { x in x * x }
mapResult // [1,4,9]

map reference on Swifter

maxElement

Returns the maximum element of a sequence

// var zeroOneTwoThree = [0,1,2,3]
maxElement(zeroOneTwoThree) //3

maxElement reference on Swifter

minElement

Return the minimum element of a sequence

// var zeroOneTwoThree = [0,1,2,3]
minElement(zeroOneTwoThree) //0

minElement reference on Swifter

prefix

Will be handled in a future post. Operates on a Sliceable.

reduce

Accumulates the result of a function on each element of sequence

let absolutePathComponents = [ "usr", "local", "bin" ]
let path = reduce(absolutePathComponents, "") { accumulate, component in accumulate + "/" + component }
path
var sum = reduce(oneTwoThree, 0) { a,x in a+x }
sum
// var oneTwoThree = [1,2,3]
reduce(oneTwoThree, 0, +)

reduce reference on Swifter

removeAll

Remove all elements from a {swift}RangeReplaceableCollectionType{/swift}, optionally requesting the storage capacity be preserved.

// var zeroOneTwoThree = [0,1,2,3]
removeAll(&zeroOneTwoThree, keepCapacity: true)
zeroOneTwoThree.capacity

removeAll reference on Swifter

removeAtIndex

Remove and return an element from a {swift}RangeReplaceableCollectionType{/swift}

zeroOneTwoThree = [0,1,2,3]
removeAtIndex(&zeroOneTwoThree, 2) //2
zeroOneTwoThree // [0,1,3]

removeAtIndex reference on Swifter

removeLast

Remove and return the last element from a nonempty {swift}RangeReplaceableCollectionType{/swift}

zeroOneTwoThree = [0,1,2,3]
removeLast(&zeroOneTwoThree)

removeLast reference on Swifter

removeRange

Remove elements within a specified index range

zeroOneTwoThree = [0,1,2,3]
removeRange(&zeroOneTwoThree, 1...2)

removeRange reference on Swifter

reverse

Reverses a {swift}CollectionType{/swift} with an index conforming to {swift}BidirectionalIndexType{/swift}

zeroOneTwoThree = [0,1,2,3]
var threeTwoOneZero = reverse(zeroOneTwoThree)

reverse reference on Swifter

sort

Sorts a mutable collection in place using the < operator or a user supplied comparison function. [swift] threeTwoOneZero // [3,2,1,0] sort(&threeTwoOneZero) threeTwoOneZero // [0,1,2,3] sort(&threeTwoOneZero) { x,y in x>y }
[/swift]
sort reference on Swifter

sorted

Returns the {swift}Array{/swift} obtained by sorting a {swift}SequenceType{/swift} using the < operator or a user supplied comparison function. [swift] let random = [1,6,2,8,3,3,2,8,7] let randomSortedAscending = sorted(random) let randomSortedDescending = sorted(random) { x,y in x>y }
randomSortedDescending
[/swift]
sorted reference on Swifter

splice

Inserts the elements of a collection into a {swift}RangeReplaceableCollectionType{/swift} at a given index.

var gap = [0,1,2,7,8,9]
var missing = [3,4,5,6]
splice(&gap, missing, atIndex:3)

splice reference on Swifter

split

let pathToSplit = "/usr/local/bin"
var splitPath = split(path) { c in c == "/" }
splitPath
splitPath = split(path, { c in c == "/" }, maxSplit:2, allowEmptySlices:true)
splitPath

split reference on Swifter

startsWith

Determines if the prefix of one {swift}SequenceType{/swift} is equivalent to another {swift}SequenceType{/swift} either using the == operator or a user defined equivalence function

let oneToFive = [1,2,3,4,5]
let oneToThree = [1,2,3]
startsWith(oneToFive, oneToThree)

let floats125 = [1.0,2.0,3.0,4.0,5.0]
let fuzzyPrefix = [1.01,1.99,3.01]
let isFuzzyPrefix = startsWith(floats125, fuzzyPrefix) { x,y in abs(x-y) < 0.02 }
isFuzzyPrefix
&#91;/swift&#93;
<a href="http://swifter.natecook.com/func/startsWith"><code>startsWith</code> reference on Swifter</a>
<h2>stride</h2>
Creates sequences from a given value, to or through a given value, steping by a given increment (or stride).
[swift]
let to = stride(from:0, to:100, by:10)
map(to) { x in println(x) }
let through = stride(from:0, through:100, by:10)
map(through) { x in println(x) }

stride reference on Swifter

underestimateCount

Will be covered in a future post.

Download the Playground

The playground for this, and all other posts in the series, can be found on GitHub in the SwiftStandardLibraryPlaygrounds repository.


Posted in Code Snippets, Swift, Swift Standard Library | Leave a comment

Hardware Review: OWC Aura Pro 480GB SSD Envoy Upgrade Kit for MacBook Air

I love my 11″ MacBook Air. But as a developer, its 120GB SSD has become an issue. With new versions of iOS, beta versions of Xcode and the various Apple programs that don’t play well with external hard drives (I am looking at you iTunes and iPhoto) I seem to be constantly shuffling stuff on and off my G|Drive slim external drive. Finally, exasperated with my new role as a human cache manager, I decided to try to find a solution.

With a quick bit of googling I quickly found the OWC Aura SSD Upgrades page. I chose the 480GB Aura Pro SSD + Envoy + Tools bundle (for $415 plus tax and shipping at time of writing). The Envoy is a case that allows you to use your old SSD as an external drive. The Pro version offers slightly faster write times and a longer warranty than the regular version.

You should be aware that Apple does not view the MacBook Air SSD as a user-upgradable item and what is described in this article may void your warranty.

Update: OWC contacted me to clarify some issues relating to warranties. For more information please see the information provided by Eileen Millard in the comments section below.

Installation

The surprisingly compact Aura Pro Envoy kit. (I though they had left something out!)

The surprisingly compact Aura Pro Envoy kit. (I though they had left something out!)

The Aura Pro Envoy kit comes with everything you need to perform the upgrade: the 480GB SSD, an enclosure to use your old SSD as an external drive, a pouch for the external enclosure, a USB cable, some screws, a user guide and last, but not least, the two special screwdrivers you need to open and close the case of your MacBook Air.

After unpacking all the contents of the kit, I pointed my iPad to an installation video and began.

Contents of the Auro Pro SSD + Envoy + Tools kit.

Contents of the Auro Pro SSD + Envoy + Tools kit.

The screws on the bottom of the MacBook Air are tiny, so it was with some trepidation that I began slowly unscrewing them. I really was afraid I would strip them. I also recommend having a few cups close by to keep the various screws organized.

The installation process went remarkably smoothly and soon the new SSD was in place and I was ready to close up my machine.

View of Installed Aura Pro

View of the installed Auro Pro, just before closing case.

In all the entire procedure took about half an hour, even with my super-slow unscrewing and refastening of the case.

Data Recovery

The instructions link to by the kit recommended a fresh OS install and then a Time Machine restore, a procedure I dutifully followed.

Reinstalling Mavericks

Reinstalling Mavericks

I had been pleasantly surprised at how quickly the hardware upgrade had gone, the data recovery was another matter. It took hours to download and install Mavericks (around 4) and then I started the Time Machine recovery. I ended up letting this process run overnight. I checked on it once and the recovery had completed but it was beginning on its first backup of the new system; it seemed to think everything was new. The following morning I awoke to fully restored machine with lots of free disk space.

Performance

I wanted to make sure that the performance of the upgraded SSD was the same or better than the stock one, so before the upgrade I ran three I/O benchmarks using XBench and I repeated these afterwards. The results can be seen below; the error bars are actually indicating the minimum and maximum data rate measured in each case. Essentially the upgrade performed better or around the same in all but one of the tests – 256K random writes – but the difference seemed small and this test was less than rigorous.

SSD Performace Before and After Upgrade

SSD Performace Before and After Upgrade

A Few Weeks Later

I decided not to publish this post until I could post an after note with it, to see if I was still happy with the upgrade a few weeks later and I have to say I am. It really has been great to be able to have multiple versions (5 at the time of writing) of Xcode on my laptop and multiple copies of my projects compiled with each one while trying validate builds and track down any errors. Had I realized the difference it would make I would have done this much sooner.


Posted in Hardware, Review | 1 Comment

Swift Standard Library: Generators, Sequences and Collections

A large part of the Swift Standard Library is concerned with {swift}Generators{/swift}, {swift}Sequences{/swift} and {swift}Collections{/swift} and functions that operate on them, so it’s pretty important to have a good understanding of them.

Generators

A {swift}Generator{/swift} is anything that conforms to the {swift}GeneratorType{/swift} protocol.
It’s fairly simple.

protocol GeneratorType {
  typealias Element
  mutating func next() -> Element?
}

So a generator is simply something that can give you the next element of some sequence of elements. If there is no next element it returns {swift}nil{/swift}.

With this information, we could create a generator, say, of powers of two.

import UIKit

/* convenience function */
func pow2(power: Int) -> Int
{
  return Int(pow(2.0, Double(power)))
}

struct PowersOfTwoGenerator1 : GeneratorType {
  typealias Element = Int
  var power : Int = 0
  mutating func next() -> Element?
  {
    return pow2(power++)
  }
}

This code conforms to the protocol and is a valid {swift}GeneratorType{/swift} but it is not very easy to use. It will produce an infinite number of elements, without external logic.

For example, to print the first 10 powers we would need to do the following:

var n=10 
var g = PowersOfTwoGenerator1()
while n-- > 0 {
  println(g.next()!)
}

We can make it a little easier to use by adding an initializer to set a limit
on how many values we will print.

struct PowersOfTwoGenerator2 : GeneratorType {
    typealias Element = Int
    var power : Int = 0
    let endPower : Int
    init(end : Int)
    {
        endPower = end
    }
    mutating func next() -> Element?
    {
        return (power < endPower) ? pow2(power++) : nil
    }
}
&#91;/swift&#93;
This version is much easier to use.
&#91;swift&#93;
var g2 = PowersOfTwoGenerator2(end:10)
while let x = g2.next() {
    println(x)
}
&#91;/swift&#93;
OK, so now that we have a generator what can we do with it? Well the answer to
that is... not very much. Very few of the Standard Library Routines take a {swift}GeneratorType{/swift} directly; they require a sequence.

<h2>Sequences</h2>

A sequence is anything that conforms to the {swift}SequenceType{/swift} protocol. It's defined as:
[swift]
protocol SequenceType : _Sequence_Type {
    typealias Generator : GeneratorType
    func generate() -> Generator
}

Essentially a sequence is a generator factory; something that knows how to make
generators for a sequence.

A first attempt at a power of 2 sequence might look something like this.

struct PowersOfTwoSequence2 : SequenceType
{
    typealias Generator = PowersOfTwoGenerator2
    let endPower : Int
    init(end: Int)
    {
        self.endPower = end
    }
    func generate() -> Generator {
        return Generator(end: self.endPower)
    }
}

As a first attempt this is not bad. This code works and have new capabilities, for example, we can now write:

for x in PowersOfTwoSequence2(end:10)
{
    println(x)
}

But there is a problem. It’s easier to see if we move the generator inside the
sequence class.

struct PowersOfTwoSequence3 : SequenceType
{
    let endPower : Int
    struct Generator : GeneratorType {
        typealias Element = Int
        var power : Int = 0
        var endPower : Int
        init(end : Int)
        {
            endPower = end
        }
        mutating func next() -> Element?
        {
            return (power < endPower) ? pow2(power++) : nil
        }
    }
    init(end: Int)
    {
        self.endPower = end
    }
    func generate() -> Generator {
        return Generator(end: self.endPower)
    }
}

Hopefully now the problem is plain to see. There is a lot of code repetition here. The two inits are almost identical, the {swift}endPower{/swift} variable is repeated. Surely we can do better? And, of course, we can.

struct PowersOfTwoSequence4 : SequenceType
{
    let endPower : Int
    init(end: Int)
    {
        self.endPower = end
    }
    func generate() -> GeneratorOf<Int> {
        var power : Int = 0
        var nextClosure : () -> Int? = {
            (power < self.endPower) ? pow2(power++) : nil
        }
        return GeneratorOf<Int>(nextClosure)
    }
}

It’s a little subtle what’s going on here, so let’s dig a little deeper. All
the generator logic has been moved into a closure {swift}nextClosure{/swift}.
The closure captures the {swift}endPower{/swift} from the enclosing class and the current
{swift}power{/swift} from the {swift}generate{/swift} function. Finally, the {swift}GeneratorOf{/swift} class is a
Standard Library Class that conforms to {swift}GeneratorType{/swift} and
knows how to use the closure to implement the {swift}next{/swift} method.

Using trailing closure and type inference we can also write this as:

struct PowersOfTwoSequence5 : SequenceType
{
    let endPower : Int
    init(end: Int)
    {
        self.endPower = end
    }
    func generate() -> GeneratorOf<Int> {
        var power : Int = 0
        return GeneratorOf<Int> {
            (power < self.endPower) ? pow2(power++) : nil
        }
    }
}

for x in PowersOfTwoSequence5(end:10)
{
    println(x)
}
&#91;/swift&#93;

<h2>Collections</h2>
A collection a sequence that conforms to the {swift}CollectionType{/swift} protocol.
The {swift}CollectionType{/swift} protocol is defined as follows.
[swift]
protocol _CollectionType : _SequenceType {
    typealias Index : ForwardIndexType
    var startIndex: Index { get }
    var endIndex: Index { get }
    typealias _Element
    subscript (_i: Index) -> _Element { get }
}
protocol CollectionType : _CollectionType, SequenceType {
    subscript (position: Self.Index) -> Self.Generator.Element { get }
    }

So a {swift}CollectionType{/swift} is a {swift}SequenceType{/swift} that can be accessed via a subscript and defines a startIndex and endIndex.

We can upgrade our {swift}PowersOfTwoSequence{/swift} to a {swift}Collection{/swift} with a few small code changes.

struct PowersOfTwoCollection : CollectionType
{
    typealias Index = Int
    let startIndex : Int
    let endIndex : Int
    init(start:Int, end: Int)
    {
	self.startIndex = start
        self.endIndex = end
    }
    func generate() -> GeneratorOf<Int> {
        var power : Int = 0
        return GeneratorOf<Int> {
            (power < self.endIndex) ? pow2(power++) : nil
        }
    }
    subscript(i: Index) -> Int { return pow2(i) }
}

While many standard library functions can operate on sequences, some,
for example {swift}reverse{/swift} require an object conforming to {swift}CollectionType{/swift}.

/* Now that we're a collection we can go backwards! */
for x in reverse(PowersOfTwoCollection(start:0,end:10)) {
    println(x)
}

Conclusion

In this post I have examined the three main protocols that Swift uses to underpin many of its functions that operate on sequences and collections and presented example code for each one.

A playground containing all the code from this post is available in the GitHub repository SwiftStandardLibraryPlaygrounds


Posted in Swift, Swift Standard Library, Tutorial | Tagged , , , , | Leave a comment