Skip to content

Instantly share code, notes, and snippets.

@miguelfermin
Created March 1, 2016 11:06
Show Gist options
  • Save miguelfermin/1e37a45134f143c7e1c5 to your computer and use it in GitHub Desktop.
Save miguelfermin/1e37a45134f143c7e1c5 to your computer and use it in GitHub Desktop.
Swift Functional Programming: Filters
// 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