在Swift中用字典对数组元素进行分组
hudson 译 原文
想象一下,您有一个Device
对象数组,并且您想按类别对它们进行分组,如下图所示:
你应该如何解决这个问题?
在Swift 5之前,最直接的方法是循环遍及数组中的每个设备,并手动将每个元素分配给其各自的类别。在Swift 5中,苹果引入了范型字典初始化器,以帮助开发人员只需一行代码即可处理这种情况。
init(grouping:by:)介绍
在Swift 5中,苹果引入了“分组”字典初始化器。根据文档,初始化器有以下定义:
创建一个新的字典,其键是给定闭包返回的分 组,其值是返回每个键的元素的数组。
为了更好地理解定义,让我们重温我们在本文开头看到的示例。
假设您有一个Device
结构和一个Device
对象数组,如下所示:
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”)
]
要按类别对所有Device
数组进行分组,我们可以通过创建一个新的字典,并向其初始化器提供源数组和一个闭包,该闭包返回需要进行分组的键。 看看下面的代码片段:
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”)
]
]
*/
如您所见,我们只需要传递设备数组并将类别作为分组键返回,初始化器将为我们处理分组。
我们甚至可以通过使用Swift中的速记参数名称,将上述代码片段进一步简化为一行代码。
let groupByCategory = Dictionary(grouping: deviceArray) { $0.category }
很整洁,不是吗?
上面的示例演示了使用初始化器的最标准方式。然而,由于初始化器允许我们定义确定分组键的闭包,因此它比这灵活得多。
通过使用相同的deviceArray
数组 ,假设我们想将所有苹果产品组合在一起,我们实际上可以定义一个闭包,检查设备名称,并将所有设备分组为包含“Macbook”和“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”)
]
]
*/
按自定义对象分组
在本节中,我们将研究如何使用自定义对象作为init(grouping:by:)初始化器的分组键。
出于演示目的,让我们通过定义Company
公司结构来更新前面的示例,并将company
变量添加到设备结构中。随后,我们将尝试按公司对所有设备进行分组。
struct Company {
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)
]
接下来,让我们检查Dictionary
结构的定义,找出成为字典键需要满足的要求。
public struct Dictionary<Key, Value> where Key : Hashable
从上述定义中可以看出,任何符合Hashable协议的对象都可以用作字典键。
专业提示:
查看这篇很棒的文章,了解有关Hashable协议的更多信息。
因此,我们可以继续使Company
结构符合Hashable
协议,并利用init(grouping:by:)
初始化器按公司对所有设备进行分组。
// 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 }
就这些,我们已经成功地按公司对所有设备对象进行了分组。
正如Reddit用户svetlyo所建议的那样,我们可以通过使用键路径语法使代码更加简洁。
let groupByCategory = Dictionary(grouping: deviceArray, by: \.category)
小结
字典的 Init(grouping:by:)
初始化器非常有用,并且非常易于使用。
当我想把数组数据分组到字典中,以便在具有多个节的表格视图或集合视图上显示它们时,我发现它特别方便。
下次您想创建包含多个节(Section)的表格视图时,请务必尝试此方法。
我希望这篇文章能让您清楚地了解如何正确使用Dictionary.init(grouping:by:)
初始化器。
如果您喜欢这篇文章,请随时查看我的其他
与Swift相关的文章
如果您有任何问题,请随时在下面的评论部分留下,或者您可以在
推特上联系我。
感谢您的阅读。🧑🏻💻
原文链接:https://juejin.cn/post/7357301805568851979 作者:hudson2022