before

Suppose we are developing an item page and the requirement is to section the item, but the data returned to us in the background is an array of items for the entire list. Before Swift 5, we could only group by iterating through groups:

struct Shop {
    let name: String
    let category: String
}

let shops = [Shop(name: "iPhone 11", category: "phone"),
             Shop(name: "iPhone XR", category: "phone"),
             Shop(name: "Redmi note8", category: "phone"),
             Shop(name: "WeiLong", category: "food"),
             Shop(name: Lao Gan Ma, category: "food")]

let allCategory = Set(shops.map { $0.category })
var shopSections = [String: [Shop]]()
allCategory.forEach { (cate) in
    let cateShops = shops.filter { $0.category == cate }
    shopSections[cate] = cateShops
}
Copy the code

now

With Swift 5.0, Dictionary has a new initialization method: init(Grouping :by:). This method organizes the array into a dictionary using the key returned in the closure. Rewrite the above code with this method:

let shopSections = Dictionary(grouping: shops) { (shop) -> String in
    return shop.category
}
Copy the code

The code above can be made more concise by Swift’s syntax:

let shopSections = Dictionary(grouping: shops) { $0.category }
Copy the code

More and more

Because this method provides a closure for us to operate on, we can not only return the fields of the current model, but we can also be flexible as needed. For example, in the example above, let’s say our requirements change to categorizing goods by where they belong. Although the field returned in the background does not return, we can still judge by the goods:

let shopSections = Dictionary(grouping: shops) { (shop) -> String in
    if shop.name.contains("iPhone") {
        return "US"
    }
    return "China"
}

print(shopSections)
/*
["US": [DataStructureDemo.Shop(name: "iPhone 11", category: "phone"), DataStructureDemo.Shop(name: "iPhone XR", category: "phone")]."China": [DataStructureDemo.Shop(name: "Redmi note8", category: "phone"), DataStructureDemo.Shop(name: "WeiLong", category: "food"),
DataStructureDemo.Shop(name: "French fries", category: "food"* /)]]Copy the code

explore

We all know that you can use dictionary keys as long as you follow Hashable data types, such as Int, String, etc. So, we can also use a structure as a dictionary key, as long as it complies with the protocol:

struct Company: Hashable {
    let name: String
}

struct Shop {
    let name: String
    let category: String
    let company: Company
    
}

let apple = Company(name: The word "apple")
let littleMi = Company(name: "Millet")
let wl = Company(name: "WeiLong")
let lgm = Company(name: Lao Gan Ma)


let shops = [Shop(name: "iPhone 11", category: "phone", company: apple),
             Shop(name: "iPhone XR", category: "phone", company: apple),
             Shop(name: "Redmi note8", category: "phone", company: littleMi),
             Shop(name: "WeiLong", category: "food", company: wl),
             Shop(name: "French fries", category: "food", company: lgm)]


let shopSections = Dictionary(grouping: shops) { return $0.company }

print(shopSections)
/*
[DataStructureDemo.Company(name: "Millet"): [DataStructureDemo.Shop(name: "Redmi note8", category: "phone", company: DataStructureDemo.Company(name: "Millet"))], DataStructureDemo.Company(name: The word "apple"): [DataStructureDemo.Shop(name: "iPhone 11", category: "phone", company: DataStructureDemo.Company(name: The word "apple")), DataStructureDemo.Shop(name: "iPhone XR", category: "phone", company: DataStructureDemo.Company(name: The word "apple"))], DataStructureDemo.Company(name: "WeiLong"): [DataStructureDemo.Shop(name: "WeiLong", category: "food", company: DataStructureDemo.Company(name: "WeiLong"))], DataStructureDemo.Company(name: Lao Gan Ma): [DataStructureDemo.Shop(name: "French fries", category: "food", company: DataStructureDemo.Company(name: Lao Gan Ma* /))]]Copy the code

Hopefully this article gives you a good idea of how to use Init (Grouping :by:) to be more efficient. 😄