Grouping Array Elements With Dictionary in Swift

栏目: IT技术 · 发布时间: 4年前

内容简介:Imagine you have an array ofHow should you go about in solving this problem?Before Swift 5, the most straightforward way is to loop through each device in the array and manually assign each element to its respective category. In Swift 5, Apple has introduc

Imagine you have an array of Device objects and you want to group them by category as shown in the image below:

Grouping Array Elements With Dictionary in Swift
Grouping Device object by category

How should you go about in solving this problem?

Before Swift 5, the most straightforward way is to loop through each device in the array and manually assign each element to its respective category. In Swift 5, Apple has introduced a generic dictionary initializer to help developers deal with this kind of situation with just 1 single line of code.

Wondering how this can be done? Read on to find out more.

Introducing init(grouping:by:)

In Swift 5, Apple introduced a “grouping by” dictionary initializer. According to the documentation , the initializer has a definition of:

Creates a new dictionary whose keys are the groupings returned by the given closure and whose values are arrays of the elements that returned each key.

apple.com

To better understand the definition, let’s revisit the example that we saw at the beginning of this article.

Let’s say you have a Device struct and an array of Device objects as shown below:

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

let deviceArray = [
    Device(category: "Laptop", name: "Macbook Air"),
    Device(category: "Laptop", name: "Macbook Pro"),
    Device(category: "Laptop", name: "Galaxy Book"),
    Device(category: "Laptop", name: "Chromebook"),
    Device(category: "Mobile Phone", name: "iPhone SE"),
    Device(category: "Mobile Phone", name: "iPhone 11"),
    Device(category: "Mobile Phone", name: "Galaxy S"),
    Device(category: "Mobile Phone", name: "Galaxy Note"),
    Device(category: "Mobile Phone", name: "Pixel")
]

To group all Device objects by category, we can initialize a dictionary by giving its initializer the source array and a closure that returns the grouping key. Take a look at the code snippet below:

let groupByCategory = Dictionary(grouping: deviceArray) { (device) -> String in
    return device.category
}

/*
// Output of groupByCategory equivalent to:
[
    "Laptop": [
        Device(category: "Laptop", name: "Macbook Air"),
        Device(category: "Laptop", name: "Macbook Pro"),
        Device(category: "Laptop", name: "Galaxy Book"),
        Device(category: "Laptop", name: "Chromebook")
    ],
    "Mobile Phone": [
        Device(category: "Mobile Phone", name: "iPhone SE"),
        Device(category: "Mobile Phone", name: "iPhone 11"),
        Device(category: "Mobile Phone", name: "Galaxy S"),
        Device(category: "Mobile Phone", name: "Galaxy Note"),
        Device(category: "Mobile Phone", name: "Pixel")
    ]
]
*/

As you can see, we just need to pass in the Device array and return the category as the grouping key, the initializer will take care of the grouping for us. 

Grouping Array Elements With Dictionary in Swift
Dictionary.init(grouping:by:) in action

We can even further simplify the above code snippet into a single line of code by using the shorthand argument names in Swift.

let groupByCategory = Dictionary(grouping: deviceArray) { $0.category }

Pretty neat isn’t it?

The above example demonstrates the most standard way of using the initializer. However, since the initializer allows us to define a closure that determines the grouping key, it is much more flexible than that.

By using the same deviceArray , let’s say we would like to group all Apple products together, we can actually define a closure that checks for the device ‘s name and group all devices with a name that contains “Macbook” and “iPhone”.

let groupByCategoryWithApple = Dictionary(grouping: deviceArray) { (device) -> String in
    
    // Group all devices that name contain the word "Macbook" and "iPhone"
    if device.name.contains("Macbook") || device.name.contains("iPhone") {
        return "Apple"
    } else {
        return "Others"
    }
}

/*
// Output of groupByCategoryWithApple equivalent to:
[
    "Apple": [
        Device(category: "Laptop", name: "Macbook Air"),
        Device(category: "Laptop", name: "Macbook Pro"),
        Device(category: "Mobile Phone", name: "iPhone SE"),
        Device(category: "Mobile Phone", name: "iPhone 11"),
    ],
    "Others": [
        Device(category: "Laptop", name: "Galaxy Book"),
        Device(category: "Laptop", name: "Chromebook"),
        Device(category: "Mobile Phone", name: "Galaxy S"),
        Device(category: "Mobile Phone", name: "Galaxy Note"),
        Device(category: "Mobile Phone", name: "Pixel")
    ]
]
*/

Group by Custom Object

In this section, we will look at how we can use a custom object as the grouping key of the init(grouping:by:) initializer.

For demo purposes, let’s update the previous example by defining a Company struct and add a company variable to the Device struct. We will try to group all the devices by company in just a moment.

struct Company: Hashable {
    let name: String
    let founder: String
}

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

// Define Company objects
let samsung = Company(name: "Samsung", founder: "Lee Byung-chul")
let apple = Company(name: "Apple", founder: "Steve Jobs")
let google = Company(name: "Google", founder: "Larry Page")

let deviceArray = [
    Device(category: "Laptop", name: "Macbook Air", company: apple),
    Device(category: "Laptop", name: "Macbook Pro", company: apple),
    Device(category: "Laptop", name: "Galaxy Book", company: samsung),
    Device(category: "Laptop", name: "Chromebook", company: google),
    Device(category: "Mobile Phone", name: "iPhone SE", company: apple),
    Device(category: "Mobile Phone", name: "iPhone 11", company: apple),
    Device(category: "Mobile Phone", name: "Galaxy S", company: samsung),
    Device(category: "Mobile Phone", name: "Galaxy Note", company: samsung),
    Device(category: "Mobile Phone", name: "Pixel", company: google)
]

Next, let’s examine the definition of the Dictionary struct to find out the requirements that need to be fulfilled in order to become a dictionary key.

public struct Dictionary<Key, Value> where Key : Hashable

As can be seen from the above definition, any object that conforms to the Hashable protocol can be used as a dictionary key.

Pro tip:

Check out this great article to learn more about the Hashable protocol.

Therefore, we can go ahead and conform the Company struct to the Hashable protocol and leverage the init(grouping:by:) initializer to group all the devices by company.

// Conform to Hashable protocol
struct Company: Hashable {
    let name: String
    let founder: String
}

// ...
// ...

// Use Company object as grouping key
let groupByCompany = Dictionary(grouping: deviceArray) { $0.company }

That’s it, we have successfully group all the Device objects by company.

Wrapping Up

The init(grouping:by:) initializer is extremely useful and very easy to use.

I find it comes in especially handy when I want to group an array of data into a dictionary in order to show them on a table view or collection view with multiple sections.

Next time when you want to create a table view with multiple sections, make sure to give this method a try.

I hope this article can give you a clear idea on how to use the Dictionary.init(grouping:by:) initializer correctly.

If you like this article, feel free to check out my other articles related to Swift .

If you have any questions, feel free to leave it in the comment section below or you can reach out to me on Twitter .

Thanks for reading. ‍:computer:


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

零工经济

零工经济

Diane Mulcahy / 陈桂芳 / 中信出版集团股份有限公司 / 2017-11-1 / CNY 39.00

// 国内第一本讲述“零工经济”概念的图书! // 互联网时代,你的技能与兴趣可以与市场需求产生更佳的匹配! // 通过工作模式的转型,你的财务状况可以获得更多的灵活性与稳定性! 如果把当前的工作世界看作一把尺子,设想它一头是传统意义上由企业提供的职业阶梯,另一头是失业,那么两头之间范围广、种类多的工作选择便是零工经济。它包括咨询顾问、承接协定、兼职工作、临时工作、自由职业、个体......一起来看看 《零工经济》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具