Example

Let's take a look at what this looks like in practice. We can use some of the techniques we learned in this chapter to write a different and possibly better implementation of our party inviter.

We can start by defining the same input data:

//: List of people to invite
let invitees = [
    "Sarah",
    "Jamison",
    "Marcos",
    "Roana",
    "Neena",
]

//: Dictionary of shows organized by genre
var showsByGenre = [
    "Comedy": "Modern Family",
    "Drama": "Breaking Bad",
    "Variety": "The Colbert Report",
]

In this implementation, we are making the invitees list, which is just a constant list of names and the shows by genre dictionary variable. This is because we are going to be mapping our invitees list to a list of invitation text. As we do the mapping, we will have to pick a random genre to assign to the current invitee, and in order to avoid assigning the same genre more than once, we can remove the genre from the dictionary.

So let's write the random genre function:

func pickAndRemoveRandomGenre() -> (genre: String, example: String)? {
    let genres = Array(showsByGenre.keys)
    guard genres.count > 0 else {
        return nil
    }

    let genre = genres[Int(rand()) % genres.count]
    let example = showsByGenre[genre]!
    showsByGenre[genre] = nil
    return (genre: genre, example: example)
}

We start by creating an array of just the keys of the shows by genre dictionary. Then, if there are no genres left, we simply return nil. Otherwise, we pick out a random genre, remove it from the dictionary, and return it and the show example.

Now we can use that function to map the invitees to a list of invitations:

let invitations: [String] = invitees
.map({ name in
    guard let (genre, example) = pickAndRemoveRandomGenre() else {
        return "(name), just bring yourself"
    }
    return "(name), bring a (genre) show"
        + "
(example) is a great (genre)"
})

Here we try to pick a random genre. If we can't, we return an invitation saying that the invitee should just bring themselves. If we can, we return an invitation saying what genre they should bring with the example show. The one new thing to note here is that we are using the sequence " " in our string. This is a newline character and it signals that a new line should be started in the text.

The last step is to print out the invitations. To do that, we can print out the invitations as a string joined by newline characters:

print(invitations.joinWithSeparator("
"))

This works pretty well but there is one problem. The first invitees we listed will always be assigned a genre because the order they are processed in never changes. To fix this, we can write a function to shuffle the invitees before we begin to map the function:

func shuffle(array: [String]) -> [String] {
    return array
        .map({ ($0, Int(rand())) })
        .sort({ $0.1 < $1.1 })
        .map({$0.0})
}

In order to shuffle an array, we go through three steps: First, we map the array to a tuple with the original element and a random number. Second, we sort the tuples based on those random numbers. Finally, we map the tuples back to just their original elements.

Now, all we have to do is add a call to this function to our sequence:

let invitations: [String] = shuffle(invitees)
.map({ name in
    guard let (genre, example) = pickAndRemoveRandomGenre() else {
        return "(name), just bring yourself"
    }
    return "(name), bring a (genre) show"
        + "
(example) is a great (genre)"
})

This implementation is not necessarily better than our previous implementations, but it definitely has its advantages. We have taken steps towards reducing the state by implementing it as a series of data transformations. The big hiccup in that is that we are still maintaining state in the genre dictionary. We can certainly do more to eliminate that as well, but this gives you a good idea of how we can start to think about problems in a functional way. The more ways in which we can think about a problem, the higher our odds of coming up with the best solution.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset