Swift Arrays – Basic forEach, map & filter — July 10, 2016

Swift Arrays – Basic forEach, map & filter

 

I have been using Swift for quite a long while now but while trying to explain parts of it I was trying to make simple little demos of how our lives can be made easier by using the functional aspects of the language. Starting simple lets start by making an array for the ages of some people etc

var ages = [12, 54, 13, 76, 86, 34]

 

What if we wanted the ages in months? We could iterate over ages and multiply each element by 12

var agesMonths: [Int] = []

for age in ages{
	agesMonths.append(age * 12)
}

 

Alternatively we could use the forEach function on the people array. This function essentially shortens the syntax for a for in loop by taking a function as an argument and then applying it to each element in the array in index order. This does not replace the for in loop, as that has its place, for example when using continue as that is not permitted for this function.

var agesMonths1: [Int] = []
ages.forEach({agesMonths1.append($0 * 12)})

 

Incase you didn’t already know $0 is shorthand for the passed in parameter to the function. In this case it will be the Int from whichever index of the array is being iterated over. A great example of how a function can be reduced down to this level is in the Apple Swift docs here.

If we didn’t want to make a new array and just transform the elements of the original array we could use map. Map allows us to pass a function as an argument which will again be performed on each element of the array, allowing for each element to be transformed by our passed in function. In this case each element will be multiplied by 12. The difference being though that the result of the map function returns a new array consisting of the newly transformed elements.

ages = ages.map({$0 * 12})

 

Perhaps a slightly more complex example. We will make a struct Person that will have four properties.

struct Person{
	var firstName: String
	var lastName: String
	var age: Int
	var weight: Float
}

let person1 = Person.init(firstName: "Harry", lastName: "Goodwin", age: 28, weight: 10.2)
let person2 = Person.init(firstName: "Jessica", lastName: "Joop", age: 35, weight: 9.3)
let person3 = Person.init(firstName: "Mark", lastName: "Master", age: 22, weight: 10.2)
let person4 = Person.init(firstName: "Xavier", lastName: "Brand", age: 44, weight: 13.3)

var people: [Person] = [person1, person2, person3, person4]

So lets try and transform some array elements! Perhaps we wanted all of names to be uppercase? Why not make a function to do it for us that we can pass as an argument to the map function.

func personNamesUppercase(person: Person) -> Person{
	var newPerson = person
	newPerson.firstName = person.firstName.uppercaseString
	newPerson.lastName = person.lastName.uppercaseString
	
	return newPerson
}

let peopleCapitalised = people.map(personNamesUppercase)

 

Now lets print out all of the first and last names

peopleCapitalised.forEach{
	print($0.firstName)
}

 

The weights are currently in imperial measurement (stone), so lets use map again to convert them to metric (kg).

func convertWeight(person: Person) -> Person{
	var newPerson = person
	newPerson.weight = person.weight * 6.35029
	
	return newPerson
}

let peopleMetricWeight = people.map(convertWeight)

peopleMetricWeight.forEach{
	print($0.weight)
}

 

What is really cool though is that we can chain map function so we can make the names uppercase and convert the weights all in one statement

let peopleUpperCaseMetric = people.map(personNamesUppercase).map(convertWeight)

Now lets take a look at some other useful functions we can use. What if we wanted to have an array of people under 30?

let underThirties = people.filter{$0.age < 30}
print(underThirties.count)

Or perhaps people 30 or over and weighing more than 60kg. For this we will need to use the function we created earlier to convert the weights to metric and then apply a filter on age and weight.

let overThirtyover10kg = people.map(convertWeight).filter{$0.age >= 30 && $0.weight > 60}
print(overThirtyover10kg.count)

There is a playground with all of the examples on Github.

I really like the syntax for passing in functions in Swift, although it took me quite a long time to really get it never having come across it in any functional languages etc. But seeing how clean code can be made above I think it is definitely worth taking a look at.