swift拾遗(set)

222 阅读6分钟

集合类型的哈希值

要将某个类型的元素存储在集合中,该类型必须是可哈希的,也就是说,该类型必须提供一种为自身计算哈希值的方法。哈希值是一个 Int 类型的值,对于所有相等的对象,其哈希值相同,即如果 a == b,那么 a 的哈希值等于 b 的哈希值。

Swift 的所有基本类型(如 StringIntDoubleBool)默认都是可哈希的,因此可以用作集合的值类型或字典的键类型。没有关联值的枚举成员(如“枚举”部分所述)默认也是可哈希的。

注意

你可以让自定义类型遵循 Swift 标准库中的 Hashable 协议,从而将其用作集合的值类型或字典的键类型。有关实现所需的 hash(into:) 方法的信息,请参阅“Hashable”。有关遵循协议的信息,请参阅“协议”。

集合类型语法

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 的集合,用于存储 String 类型的值:

var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items

favoriteGenres 变量被声明为“一个存储 String 类型值的集合”,写作 Set<String>。由于这个特定的集合指定了值的类型为 String,所以它只允许存储 String 类型的值。在这里,favoriteGenres 集合通过一个数组字面量进行初始化,该数组字面量包含三个 String 类型的值("Rock""Classical""Hip hop")。

注意

favoriteGenres 集合被声明为变量(使用 var 关键字)而非常量(使用 let 关键字),因为在下面的示例中会对其中的元素进行添加和移除操作。

仅通过数组字面量无法推断出集合类型,因此必须显式声明 Set 类型。不过,由于 Swift 具备类型推断功能,如果你使用只包含单一类型值的数组字面量来初始化集合,就不必写出集合元素的类型。favoriteGenres 的初始化可以采用更简洁的形式来编写:

var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

由于数组字面量中的所有值都是同一类型,Swift 可以推断出 Set<String>favoriteGenres 变量应使用的正确类型。

访问和修改集合

你可以通过集合的方法和属性来访问和修改它。

要了解集合中元素的数量,可以查看其只读的 count 属性:

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."

插入

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-in 循环来遍历集合中的值。

image.png

有关 for-in 循环的更多信息,请参阅“for-in 循环”。

Swift 的 Set 类型没有定义特定的顺序。若要按特定顺序遍历集合中的值,可使用 sorted() 方法,该方法会以数组形式返回集合中的元素,数组中的元素按小于运算符(<)排序。

image.png

执行集合操作

你可以高效地执行基本的集合操作,例如将两个集合合并在一起、确定两个集合有哪些共同的值,或者判断两个集合包含的元素是完全相同、部分相同还是完全不同。

基本集合操作

下图展示了两个集合 —— ab,不同集合操作的结果用阴影区域表示。

image.png

执行集合操作

  • 使用 intersection(_:) 方法创建一个新集合,新集合仅包含两个原集合中共有的元素。
  • 使用 symmetricDifference(_:) 方法创建一个新集合,新集合包含仅存在于其中一个原集合中的元素(即不同时存在于两个集合中的元素)。
  • 使用 union(_:) 方法创建一个新集合,新集合包含两个原集合中的所有元素。
  • 使用 subtracting(_:) 方法创建一个新集合,新集合包含不在指定集合中的元素。

image.png

集合成员关系和相等性

下图展示了三个集合 —— abc,其中重叠区域表示集合间共享的元素。集合 a 是集合 b 的超集,因为 a 包含了 b 中的所有元素。相反,集合 b 是集合 a 的子集,因为 b 中的所有元素也都包含在 a 中。集合 b 和集合 c 彼此不相交,因为它们没有共同的元素。

image.png

集合成员关系和相等性判断方法

  • 使用“相等”运算符(==)来判断两个集合是否包含完全相同的元素。
  • 使用 isSubset(of:) 方法来判断一个集合的所有元素是否都包含在指定集合中。---儿子是否包含在父亲中
  • 使用 isSuperset(of:) 方法来判断一个集合是否包含指定集合中的所有元素。 ---父亲是否包含儿子
  • 使用 isStrictSubset(of:)isStrictSuperset(of:) 方法来判断一个集合是否是指定集合的真子集或真超集(即子集或超集,但不相等)。
  • 使用 isDisjoint(with:) 方法来判断两个集合是否没有共同元素。

image.png