集合在集合中存儲相同類型的不同值,沒有定義的順序。 當(dāng)元素的順序不重要時,或者當(dāng)您需要確保元素只出現(xiàn)一次時,您可以使用集合而不是數(shù)組。
集類型的哈希值
類型必須是可哈希的,以便存儲在集合中,即,類型必須提供一種計算自身的哈希值的方法。 哈希值是一個Int值,對于所有均等比較的對象是相同的,因此如果a == b,則遵循a.hashValue == b.hashValue。
Swift的所有基本類型(例如String,Int,Double和Bool)在默認(rèn)情況下是哈希的,并且可以用作設(shè)置值類型或字典鍵類型。 默認(rèn)情況下,沒有關(guān)聯(lián)值的枚舉值值(如枚舉中所述)也是可哈希的。
您可以使用自己的自定義類型作為設(shè)置值類型或字典鍵類型,使它們符合Swift標(biāo)準(zhǔn)庫中的Hashable協(xié)議。 符合Hashable協(xié)議的類型必須提供一個稱為hashValue的gettable Int屬性。 由類型的hashValue屬性返回的值不需要在同一程序的不同執(zhí)行或不同程序中相同。
因為Hashable協(xié)議符合Equatable,符合類型還必須提供equals運算符(==)的實現(xiàn)。 可等式協(xié)議要求任何符合的==的實現(xiàn)是等價關(guān)系。 也就是說,對于所有值a,b和c,==的實現(xiàn)必須滿足以下三個條件:
a == a (Reflexivity)
a == b implies b == a (Symmetry)
a == b && b == c implies a == c (Transitivity)
集合類型的語法
Swift集合的類型寫為Set <Element>,其中Element是允許集合存儲的類型。 與數(shù)組不同,集合沒有等效的字面量。
創(chuàng)建并初始化一個空集合
您可以使用初始化語法創(chuàng)建一個特定類型的空集:
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."
或者,如果上下文已經(jīng)提供類型信息(例如函數(shù)參數(shù)或已經(jīng)輸入的變量或常量),則可以使用空數(shù)組文本創(chuàng)建空集:
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>
使用數(shù)組創(chuàng)建集合
您還可以使用數(shù)組文本初始化集合,作為將一個或多個值寫入集合集合的簡寫方法。
下面的示例創(chuàng)建一個名為favoriteGenres的集合來存儲字符串值:
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
favoriteGenres變量被聲明為“一組字符串值”,寫為Set <String>。 因為此特定集合已指定值類型的字符串,它只允許存儲字符串值。 這里,favoriteGenres集合使用在數(shù)組文本中寫入的三個String值(“Rock”,“Classical”和“Hip Hop”)初始化。
集合類型不能從數(shù)組文字單獨推斷,因此必須顯式聲明類型Set。 但是,由于Swift的類型推斷,如果使用包含相同類型值的數(shù)組文本來初始化它,則不必編寫集合的類型。 favoriteGenres的初始化可以寫成更短的形式:
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
訪問和修改集合
您可以通過其方法和屬性訪問和修改集合。
要了解集合中的元素個數(shù),請是有那個其只讀計數(shù)屬性:
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."
您可以通過調(diào)用set的insert(_ :)方法將新項目添加到集合中:
favoriteGenres.insert("Jazz")
// favoriteGenres now contains 4 items
您可以通過調(diào)用集合的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()方法,該方法將使用數(shù)組的<operator運算符排序的集合的元素并返回。
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Classical
// Hip hop
// Jazz
執(zhí)行集合的操作
您可以有效地執(zhí)行基本集合操作,例如將兩個集合組合在一起,確定兩個集合具有共同的值,或者確定兩個集合是否包含所有,一些或沒有相同的值。
集合的基本操作
下面的圖示描繪了兩個集合a和b,其具有由陰影區(qū)域表示的各種集合操作的結(jié)果。

- 使用intersection(_ :)方法創(chuàng)建一個只包含兩個公共值的新集合。(交集)
- 使用symmetricDifference(_ :)方法創(chuàng)建一個新集合,其值集在兩個集合中,但不能同時存在。()
- 使用union(_ :)方法創(chuàng)建一個包含兩個集合中的所有值的新集合。(合集)
- 使用subtracting(_ :)方法創(chuàng)建一個值不在指定集中的新集。(補(bǔ)集)
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]
集合之間的關(guān)系
下面的圖示描繪了三個集合a,b和c,其中重疊區(qū)域表示在集合中共享的元素。 設(shè)置a是集合b的超集,因為a包含b中的所有元素。 相反,集合b是集合a的子集,因為b中的所有元素也包含在a中。 集合b和集合c彼此不相交,因為它們不共享公共的元素。

- 使用“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