Created
March 1, 2016 11:06
-
-
Save miguelfermin/1e37a45134f143c7e1c5 to your computer and use it in GitHub Desktop.
Swift Functional Programming: Filters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Swift Functional Programming: Filters | |
// | |
// By Miguel Fermin on 2016.01.27 | |
// | |
// Reference: http://www.raywenderlich.com/82599/swift-functional-programming-tutorial | |
import Cocoa | |
/* Find all the even numbers between 1 and 10 */ | |
// Filtering the old way ///////////////////////////////////////////////////////////////////// | |
// | |
// 1. Create an empty mutable array | |
// 2. Iterate over the numbers 1 to 10 | |
// 3. Check each number and if even, add to the array | |
var evens = [Int]() | |
for i in 1...10 { | |
if i % 2 == 0 { | |
evens.append(i) | |
} | |
} | |
// evens equal [2,4,6,8,10] | |
// This approach works fine, but the important bit -testing whether the number is even- is buried inside the for-loop. | |
// Functional Filtering ///////////////////////////////////////////////////////////////////// | |
// We create a function, "isEven" which we will pass as a parameter to the Array's filter method. | |
func isEven(num: Int) -> Bool { | |
return num % 2 == 0 | |
} | |
// Use the range operator "..." to create a Range that will be passed to an Array initializer | |
let range = 1...10 | |
// Convenient way to create an array containing the numbers 1 through 10 | |
let array = Array(range) | |
// The "filter" statement is where the functional programming takes place. This method, exposed by Array, | |
// creates and returns a new array that contains only the items for which the given function (isEven) returns true. | |
evens = array.filter(isEven) | |
// evens equal [2,4,6,8,10] | |
// Functional Filtering: concise version one ///////////////////7////////////////////////////////////////////////// | |
// We can make this program more concise by creating the Array in-line (no need for variables). | |
// Also, since functions are just named closures, we can pass a closure as the parameter to the Array's "filter" method. | |
evens = Array(1...10).filter({ (num) in num % 2 == 0 }) | |
// evens equal [2,4,6,8,10] | |
// Functional Filtering: concise version two ///////////////////////////////////////////////////////////////////// | |
// Let's take a step further in making this program more concise. | |
// If a closure returns the result a statement evaluation (true or false), we can use the short-hand argument notation | |
// where the first argument is denoted by '$0', the second '$1', third '$2', and so on. | |
evens = Array(1...10).filter({ $0 % 2 == 0 }) | |
// evens equal [2,4,6,8,10] | |
/* | |
* The functional version of the program is certainly more concise than the imperative equivalent. | |
* This example shows a few interesting features that are common to all Functional languages: | |
* | |
* 1. Higher-Order Functions: functions that can be passed as arguments to other functions | |
* 2. First-Class Functions: functions that can be treated like any other variables; assign to variables, pass as argument to other functions | |
* 3. Closures: anonymous functions you create in place | |
*/ | |
// Functional Filtering: the magic behind filter ///////////////////////////////////////////////////////////////////// | |
// Swift arrays have a number of functional methods, such as map, join, and reduce. | |
// Below is an implementation of filter that shows what goes behind the scenes in these methods. | |
/// Generic function that creates and returns a new array that contains only the items for which the | |
/// passed *predicate* function returns true. | |
/// It takes as its inputs a source array of type **T**, and a predicate function that takes an instance | |
/// of **T** and returns a **Bool**. | |
/// - parameter source: An array of type **T** containing the elements to test against *predicate*. | |
/// - parameter predicate: A predicate function containg a test condition to apply to each element of *source*. | |
/// It takes an instance of **T** and returns a **Bool**. | |
/// - returns: An array containing the elements of *source* that passed the test condition of *predicate*. | |
func filter<T>(source: [T], predicate: (T) -> Bool) -> [T] { | |
var result = [T]() | |
for i in source { | |
if predicate(i) { | |
result.append(i) | |
} | |
} | |
return result | |
} | |
evens = filter(Array(1...10)) { $0 % 2 == 0 } | |
// evens equal [2,4,6,8,10] | |
//////////////////// | |
// Uses of filter // | |
//////////////////// | |
// Example 1 | |
let family = ["milady", "pedro", "damari", "miguel", "yamile", "giselle", "erika", "antonio", "hailey", "ashley", "noah"] | |
let filtered = family.filter { $0.characters.first == "a" } | |
// filtered equals ["antonio", "ashley"] | |
// Example 2 | |
class Car { | |
var make: String | |
var model: String | |
var color: String | |
var year: Int | |
var price: Double? | |
init(make: String, model: String, color: String, year: Int) { | |
self.make = make | |
self.model = model | |
self.color = color | |
self.year = year | |
} | |
} | |
let cars = [ | |
Car(make: "Honda", model: "Accord", color: "Black", year: 2013), | |
Car(make: "Toyota", model: "Camry", color: "Blue", year: 2015), | |
Car(make: "Nissan", model: "Maxima", color: "White", year: 2014), | |
Car(make: "Ford", model: "Fusion", color: "Black", year: 2010) | |
] | |
cars[0].price = 21000 | |
cars[3].price = 25000 | |
let newerCars = filter(cars) { $0.year >= 2014 } | |
newerCars | |
let blackCars = cars.filter { $0.color == "Black" } | |
blackCars | |
let carsWithPrice = cars.filter { $0.price != nil } | |
carsWithPrice | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment