Swift-存储类型-集合
集合在集合中存储相同类型的不同值,没有定义的顺序。 当元素的顺序不重要时,或者当您需要确保元素只出现一次时,您可以使用集合而不是数组。
集类型的哈希值
类型必须是可哈希的,以便存储在集合中,即,类型必须提供一种计算自身的哈希值的方法。 哈希值是一个Int值,对于所有均等比较的对象是相同的,因此如果a == b,则遵循a.hashValue == b.hashValue。
Swift的所有基本类型(例如String,Int,Double和Bool)在默认情况下是哈希的,并且可以用作设置值类型或字典键类型。 默认情况下,没有关联值的枚举值值(如枚举中所述)也是可哈希的。
您可以使用自己的自定义类型作为设置值类型或字典键类型,使它们符合Swift标准库中的Hashable协议。 符合Hashable协议的类型必须提供一个称为hashValue的gettable Int属性。 由类型的hashValue属性返回的值不需要在同一程序的不同执行或不同程序中相同。
因为Hashable协议符合Equatable,符合类型还必须提供equals运算符(==)的实现。 可等式协议要求任何符合的==的实现是等价关系。 也就是说,对于所有值a,b和c,==的实现必须满足以下三个条件:
a == a (Reflexivity)
a == b implies b == a (Symmetry)
a == b && b == c implies a == c (Transitivity)
集合类型的语法
Swift集合的类型写为Set <Element>,其中Element是允许集合存储的类型。 与数组不同,集合没有等效的字面量。
创建并初始化一个空集合
您可以使用初始化语法创建一个特定类型的空集:
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// Prints "letters is of type Set<Character> with 0 items."
或者,如果上下文已经提供类型信息(例如函数参数或已经输入的变量或常量),则可以使用空数组文本创建空集:
letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set<Character>
使用数组创建集合
您还可以使用数组文本初始化集合,作为将一个或多个值写入集合集合的简写方法。
下面的示例创建一个名为favoriteGenres的集合来存储字符串值:
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
favoriteGenres变量被声明为“一组字符串值”,写为Set <String>。 因为此特定集合已指定值类型的字符串,它只允许存储字符串值。 这里,favoriteGenres集合使用在数组文本中写入的三个String值(“Rock”,“Classical”和“Hip Hop”)初始化。
集合类型不能从数组文字单独推断,因此必须显式声明类型Set。 但是,由于Swift的类型推断,如果使用包含相同类型值的数组文本来初始化它,则不必编写集合的类型。 favoriteGenres的初始化可以写成更短的形式:
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
访问和修改集合
您可以通过其方法和属性访问和修改集合。
要了解集合中的元素个数,请是有那个其只读计数属性:
print("I have \(favoriteGenres.count) favorite music genres.")
// Prints "I have 3 favorite music genres."
使用布尔isEmpty属性作为检查count属性是否等于0的快捷方式:
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
// Prints "I have particular music preferences."
您可以通过调用set的insert(_ :)方法将新项目添加到集合中:
favoriteGenres.insert("Jazz")
// favoriteGenres now contains 4 items
您可以通过调用集合的remove(_ :)方法从集合中删除元素,如果该元素是集合的成员,则会删除该元素,并返回删除的值,如果集合不包含该值,则返回nil。 或者,集合中的所有元素都可以使用removeAll()方法删除。
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
// Prints "Rock? I'm over it."
要检查集合是否包含特定项目,请使用contains(_ :)方法。
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
// Prints "It's too funky in here."
遍历集合
for genre in favoriteGenres {
print("\(genre)")
}
// Jazz
// Hip hop
// Classical
Swift的Set类型没有定义的顺序。 要以特定顺序迭代集合的值,请使用sorted()方法,该方法将使用数组的<operator运算符排序的集合的元素并返回。
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Classical
// Hip hop
// Jazz
执行集合的操作
您可以有效地执行基本集合操作,例如将两个集合组合在一起,确定两个集合具有共同的值,或者确定两个集合是否包含所有,一些或没有相同的值。
集合的基本操作
下面的图示描绘了两个集合a和b,其具有由阴影区域表示的各种集合操作的结果。
屏幕快照 2016-11-19 上午11.05.07.png
- 使用intersection(_ :)方法创建一个只包含两个公共值的新集合。(交集)
- 使用symmetricDifference(_ :)方法创建一个新集合,其值集在两个集合中,但不能同时存在。()
- 使用union(_ :)方法创建一个包含两个集合中的所有值的新集合。(合集)
- 使用subtracting(_ :)方法创建一个值不在指定集中的新集。(补集)
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
集合之间的关系
下面的图示描绘了三个集合a,b和c,其中重叠区域表示在集合中共享的元素。 设置a是集合b的超集,因为a包含b中的所有元素。 相反,集合b是集合a的子集,因为b中的所有元素也包含在a中。 集合b和集合c彼此不相交,因为它们不共享公共的元素。
屏幕快照 2016-11-19 上午11.12.17.png
- 使用“is equal”运算符(==)来确定两个集合是否包含所有相同的值。
- 使用isSubset(of :)方法来确定集合的所有值是否都包含在指定的集合中。
- 使用isSuperset(of :)方法来确定集合是否包含指定集合中的所有值。
- 使用isStrictSubset(of :)或isStrictSuperset(of :)方法来确定集合是否为子集或超集,但不等于指定的集合。
- 使用isDisjoint(with :)方法来确定两个集合是否具有任何共同的值。
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true