Swift: Map, Flat Map, Filter and Reduce

by DaoNM2
765 views

Xin chào mọi người.
Trong swift có một số tính năng rất hay đó là Higher Order Function. Nó có một số hàm như là map, CompactMap, Filter and Reduce được sử dụng cho các kiểu dữ liệu dạng collection.

Khởi tạo giá trị mẫu

struct Person {
    let name: String
    let age: Int
    let pets: [String]
}
struct Pet {
    let name: String
    let age: Int
}

var peopleArray = [Person(name: "Jack", age: 11, pets: ["Dog", "Cat"]),
                   Person(name: "Queen", age: 12, pets: ["Pig"]),
                   Person(name: "King", age: 13, pets: [])]

MAP

Trước khi sử dụng chúng ta cùng tìm hiểu về syntax của hàm này trước nhé:

let resultCollection = inputCollection.map { (elementOfCollection) -> ResultType in
   return ResultType()
}

Nhìn vào đoạn code trên ta có thể hiểu hàm này sẽ trả về cho ta một collection có kiểu dữ liệu là ResultType( Một kiểu dữ liệu bất kì mà bạn mong muốn, nó có thể là Int, Double, String …)

OK, Giờ chúng ta đi vào code mẫu để dễ hiểu hơn

Dạng đầy đủ:

var ages = peopleArray.map { (person) -> Int in
    return person.age
}
print(ages)
// OUTPUT: [11, 12, 13]

Ngoài dạng thông thường thì hàm này còn có thể viết dưới dạng rút gọn như sau:

let ages = peopleArray.map({ $0.age })
print(ages)
// OUTPUT: [11, 12, 13]

$0: ở đây được hiểu là argument đầu tiên của function map, trong trường hợp này nó sẽ đại diện cho 1 phần tử trong mảng có kiểu dữ liệu là Person

Ứng dụng:
Hàm này nên được sử dụng khi mà bạn muốn tạo một collection mới có kiểu dữ liệu khác từ 1 collection hiện tại

Flat Map

let resultCollection = inputCollection.flatMap { (elementOfCollection) -> [ResultType] in
   return [ResultType]
}

Cũng giống như hàm map, hàm flatMap cũng trả về 1 collection nhưng flat map sẽ bỏ qua các tầng (nếu có).
Để dễ hiểu hơn chúng ta sẽ đi vào ví dụ sau:

Sử dụng hàm Map:

let pets = peopleArray.map({ $0.pets })
print(pets)
//OUTPUT: [["Dog", "Cat"], ["Pig"], []]

Dạng đầy đủ:

let flatPets = peopleArray.flatMap { (person) -> [String] in
    return person.pets
}
print("Flat pets: \(flatPets)")
// OUTPUT: ["Dog", "Cat", "Pig"]

Dạng rút gọn:

let flatPets = peopleArray.flatMap({ $0.pets })
print("flatPets: \(flatPets)")
// OUTPUT: flatPets: ["Dog", "Cat", "Pig"]

Có thể thấy flat map sẽ loaị bỏ hết các tầng collection bên trong và chuyển về 1 collection chỉ còn 1 tầng duy nhất thay vì collection chứa collection như khi sử dụng hàm Map.
Ngoài ra hàm flatMap cũng bỏ đi các giá trị collection empty hoặc nil.

NOTE: Hàm flatMap chỉ trả về giá trị đúng như mong đợi khi kiểu của nó là non-optional.


Vậy trong trường hợp khai báo kiểu optional thì sao: let pets: [String]?
Trong trường hợp này hàm Flat Map sẽ trả về giá trị như hàm Map vì vậy chúng ta sẽ call flatMap thêm 1 lần nữa như sau:

let flatPetsShort = peopleArray.flatMap({ $0.pets }).flatMap({ $0 })
print("flatPetsShort: \(flatPetsShort)")
//OUTPUT: flatPetsShort: ["Dog", "Cat", "Pig"]

Ứng dụng:
Flat Map thường sử dụng trong trường hợp lọc các giá trị nil ra khỏi collection hoặc chuyển 1 collection nhiều tầng thành collection 1 tầng

Reduce

Cấu trúc hàm Reduce

let result = inputCollection.reduce(initialValue) { (result, nextElement) -> ResultType in
    return a value that can be computed in the next element.
}

Hàm reduce sẽ duyệt lần lượt các phần tử trong collection và trả về kết quả dựa trên initialValue(Giá trị khởi tạo) và phép tính ở hàm return.

Bây giờ chúng ta đi vào ví dụ để dễ hiểu hơn:

Bài toán cụ thể: Cần tính tổng số tuổi của mọi người trong collection bằng hàm Reduce thì chúng ta sẽ làm như sau:

Dạng đầy đủ:

let ageTotal = peopleArray.reduce(0) { (result, personNext) -> Int in
    return result + personNext.age
}
print(ageTotal)
// OUTPUT: 36

Dạng rút gọn:

let ageTotal2 = peopleArray.map({ $0.age }).reduce(0, +)
print(ageTotal2)
// OUTPUT: 36

Ở dạng rút gọn, để sử dụng được hàm Reduce trong trường hợp này. Chúng ta cần sử dụng hàm Map để tạo ra một collection mới, chứa các phần tử là tuổi của tất cả mọi người trước, rồi sử dụng hàm Reduce dạng rút gọn để thực hiện.

Ứng dụng:
Bạn nên sử dụng hàm Reduce khi bạn muốn kết hợp các phần tử trong collection

Filter

Cấu trúc hàm Filter

let result = inputCollection.filter { (elementOfCollection) -> Bool in 
    return (Conditions)
}

Hàm Filter sẽ trả về kết quả là 1 collection chứa tất cả các phần tử thỏa mãn điều kiện (Conditions)

Bây giờ chúng ta sẽ đi vào ví dụ cho dễ hiểu hơn:
Bài toán của chúng ta là cần lọc ra được tất cả các Person có số tuổi > 11.

Chúng ta sẽ sử dụng hàm Filter dạng đầy đủ như sau:

let result = peopleArray.filter { (person) -> Bool in
    return person.age > 11
}
print("result: \(result)")

Dạng rút gọn:

let results = peopleArray.filter({ $0.age > 11 })
print(results)

Ứng dụng:
Sử dụng khi bạn cần giải quyết bài toán lọc các phần tử trong collection có điều kiện xác định

NOTE:

print("Cảm ơn mọi người đã theo dõi bài viết của mình.\n
Mọi đóng góp cũng như góp ý, mọi người hãy comment ở phía dưới để mình có thể hoàn thiện bài viết tốt hơn.") 

THANK YOU!

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

You may also like