Collection Types (集合类型)

Swift provides three primarycollection types, known as arrays, sets, and dictionaries, for storing collections of values. Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.

Swift 语言提供Arrays、Sets和Dictionaries三种基本的集合类型用来存储集合数据。数组(Arrays)是有序数据的集。集合(Sets)是无序无重复数据的集。字典(Dictionaries)是无序的键值对的集。

Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into a collection by mistake. It also means you can be confident about the type of values you will retrieve from a collection.

Swift 语言中的Arrays、Sets和Dictionaries中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信。

Note

Swift’s array, set, and dictionary types are implemented asgeneric collections. For more on generic types and collections, seeGenerics.

Swift 的Arrays、Sets和Dictionaries类型被实现为泛型集合。更多关于泛型类型和集合,参见泛型章节。

Mutability of Collections (集合的可变性)

If you create an array, a set, or a dictionary, and assign it to a variable, the collection that is created will bemutable. This means that you can change (ormutate) the collection after it is created by adding, removing, or changing items in the collection. If you assign an array, a set, or a dictionary to a constant, that collection isimmutable, and its size and contents cannot be changed.

如果创建一个Arrays、Sets或Dictionaries并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项,或者改变集合中的数据项。如果我们把Arrays、Sets或Dictionaries分配成常量,那么它就是不可变的,它的大小和内容都不能被改变。

Note

It is good practice to create immutable collections in all cases where the collection does not need to change. Doing so makes it easier for you to reason about your code and enables the Swift compiler to optimize the performance of the collections you create.

在我们不需要改变集合的时候创建不可变集合是很好的实践。如此 Swift 编译器可以优化我们创建的集合。

Arrays (数组)

Anarraystores values of the same type in an ordered list. The same value can appear in an array multiple times at different positions.

数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。

Note

Swift’sArraytype is bridged to Foundation’sNSArrayclass. For more information about usingArraywith Foundation and Cocoa, seeWorking with Cocoa Data TypesinUsing Swift with Cocoa and Objective-C (Swift 3.0.1).

Swift 的Array类型被桥接到Foundation中的NSArray类。更多关于在Foundation和Cocoa中使用Array的信息,参见Using Swift with Cocoa and Obejective-C(Swift 3.0.1)使用 Cocoa 数据类型部分。

Array Type Shorthand Syntax (数组的简单语法)

The type of a Swift array is written in full asArray, whereElementis the type of values the array is allowed to store. You can also write the type of an array in shorthand form as[Element]. Although the two forms are functionally identical, the shorthand form is preferred and is used throughout this guide when referring to the type of an array.

写 Swift 数组应该遵循像Array这样的形式,其中Element是这个数组中唯一允许存在的数据类型。我们也可以使用像[Element]这样的简单语法。尽管两种形式在功能上是一样的,但是推荐较短的那种,而且在本文中都会使用这种形式来使用数组。

Creating an Empty Array (创建一个空数组)

You can create an empty array of a certain type using initializer syntax:

我们可以使用构造语法来创建一个由特定数据类型构成的空数组:

var someInts= [Int]()

    print("someInts is of type [Int] with\(someInts.count)items.")

// Prints "someInts is of type [Int] with 0 items."

Note that the type of thesomeIntsvariable is inferred to be[Int]from the type of the initializer.

注意,通过构造函数的类型,someInts的值类型被推断为[Int]。

Alternatively, if the context already provides type information, such as a function argument or an already typed variable or constant, you can create an empty array with an empty array literal, which is written as[](an empty pair of square brackets):

或者,如果代码上下文中已经提供了类型信息,例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:[](一对空方括号):

someInts.append(3)

// someInts now contains 1 value of type Int

someInts= []

// someInts is now an empty array, but is still of type [Int]

Creating an Array with a Default Value (创建一个带有默认值的数组)

Swift’sArraytype also provides an initializer for creating an array of a certain size with all of its values set to the same default value. You pass this initializer a default value of the appropriate type (calledrepeating): and the number of times that value is repeated in the new array (calledcount):

Swift 中的Array类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(count)和适当类型的初始值(repeating)传入数组构造函数:

var threeDoubles=Array(repeating:0.0,count:3)

// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]

Creating an Array by Adding Two Arrays Together (通过两个数组相加来创建一个数组)

You can create a new array by adding together two existing arrays with compatible types with the addition operator (+). The new array’s type is inferred from the type of the two arrays you add together:

我们可以使用加法操作符(+)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来:

var anotherThreeDoubles=Array(repeating:2.5,count:3)

// anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]

var sixDoubles=threeDoubles+anotherThreeDoubles

// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

Creating an Array with an Array Literal (用数组字面量构造数组)

You can also initialize an array with anarray literal, which is a shorthand way to write one or more values as an array collection. An array literal is written as a list of values, separated by commas, surrounded by a pair of square brackets:

我们可以使用数组字面量来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。数组字面量是一系列由逗号分割并由方括号包含的数值:

[value 1,value 2,value 3]

The example below creates an array calledshoppingListto storeStringvalues:

下面这个例子创建了一个叫做shoppingList并且存储String的数组:

var shoppingList: [String] = ["Eggs","Milk"]

// shoppingList has been initialized with two initial items

TheshoppingListvariable is declared as “an array of string values”, written as[String]. Because this particular array has specified a value type ofString, it is allowed to storeStringvalues only. Here, theshoppingListarray is initialized with twoStringvalues ("Eggs"and"Milk"), written within an array literal.

shoppingList变量被声明为“字符串值类型的数组“,记作[String]。 因为这个数组被规定只有String一种数据结构,所以只有String类型可以在其中被存取。 在这里,shoppingList数组由两个String值("Eggs"和"Milk")构造,并且由数组字面量定义。

Note

TheshoppingListarray is declared as a variable (with thevarintroducer) and not a constant (with theletintroducer) because more items are added to the shopping list in the examples below.

shoppingList数组被声明为变量(var关键字创建)而不是常量(let创建)是因为以后可能会有更多的数据项被插入其中。

In this case, the array literal contains twoStringvalues and nothing else. This matches the type of theshoppingListvariable’s declaration (an array that can only containStringvalues), and so the assignment of the array literal is permitted as a way to initializeshoppingListwith two initial items.

在这个例子中,字面量仅仅包含两个String值。匹配了该数组的变量声明(只能包含String的数组),所以这个字面量的分配过程可以作为用两个初始项来构造shoppingList的一种方式。

Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization ofshoppingListcould have been written in a shorter form instead:

由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。shoppingList的构造也可以这样写:

var shoppingList= ["Eggs","Milk"]

Because all values in the array literal are of the same type, Swift can infer that[String]is the correct type to use for theshoppingListvariable.

因为所有数组字面量中的值都是相同的类型,Swift 可以推断出[String]是shoppingList中变量的正确类型。

Accessing and Modifying an Array (访问和修改数组)

You access and modify an array through its methods and properties, or by using subscript syntax.

我们可以通过数组的方法和属性来访问和修改数组,或者使用下标语法。

To find out the number of items in an array, check its read-onlycountproperty:

可以使用数组的只读属性count来获取数组中的数据项数量:

print("The shopping list contains\(shoppingList.count)items.")

// Prints "The shopping list contains 2 items."

Use the BooleanisEmptyproperty as a shortcut for checking whether thecountproperty is equal to0:

使用布尔属性isEmpty作为一个缩写形式去检查count属性是否为0:

if shoppingList.isEmpty{

    print("The shopping list is empty.")

} else {

    print("The shopping list is not empty.")

}

// Prints "The shopping list is not empty."

You can add a new item to the end of an array by calling the array’sappend(_:)method:

也可以使用append(_:)方法在数组后面添加新的数据项:

shoppingList.append("Flour")

// shoppingList now contains 3 items, and someone is making pancakes

Alternatively, append an array of one or more compatible items with the addition assignment operator (+=):

除此之外,使用加法赋值运算符(+=)也可以直接在数组后面添加一个或多个拥有相同类型的数据项:

shoppingList+= ["Baking Powder"]

// shoppingList now contains 4 items

shoppingList+= ["Chocolate Spread","Cheese","Butter"]

// shoppingList now contains 7 items

Retrieve a value from the array by usingsubscript syntax, passing the index of the value you want to retrieve within square brackets immediately after the name of the array:

可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中:

var firstItem=shoppingList[0]

// firstItem is equal to "Eggs"

Note

The first item in the array has an index of0, not1. Arrays in Swift are always zero-indexed.

第一项在数组中的索引值是0而不是1。 Swift 中的数组索引总是从零开始。

You can use subscript syntax to change an existing value at a given index:

我们也可以用下标来改变某个已有索引值对应的数据值:

shoppingList[0] ="Six eggs"

// the first item in the list is now equal to "Six eggs" rather than "Eggs"

You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces"Chocolate Spread","Cheese", and"Butter"with"Bananas"and"Apples":

还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把"Chocolate Spread","Cheese",和"Butter"替换为"Bananas"和"Apples":

shoppingList[4...6] = ["Bananas","Apples"]

// shoppingList now contains 6 items

Note

You can’t use subscript syntax to append a new item to the end of an array.

不可以用下标访问的形式去在数组尾部添加新项。

To insert an item into the array at a specified index, call the array’sinsert(_:at:)method:

调用数组的insert(_:at:)方法来在某个具体索引值之前添加数据项:

shoppingList.insert("Maple Syrup",at:0)

// shoppingList now contains 7 items

// "Maple Syrup" is now the first item in the list

This call to theinsert(_:at:)method inserts a new item with a value of"Maple Syrup"at the very beginning of the shopping list, indicated by an index of0.

这次insert(_:at:)方法调用把值为"Maple Syrup"的新数据项插入列表的最开始位置,并且使用0作为索引值。

Similarly, you remove an item from the array with theremove(at:)method. This method removes the item at the specified index and returns the removed item (although you can ignore the returned value if you do not need it):

类似的我们可以使用remove(at:)方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):

let mapleSyrup=shoppingList.remove(at:0)

// the item that was at index 0 has just been removed

// shoppingList now contains 6 items, and no Maple Syrup

// shoppingList 现在只有6项,而且不包括 Maple Syrup

// the mapleSyrup constant is now equal to the removed "Maple Syrup" string

// mapleSyrup 常量的值等于被移除数据项的值 "Maple Syrup"

Note

If you try to access or modify a value for an index that is outside of an array’s existing bounds, you will trigger a runtime error. You can check that an index is valid before using it by comparing it to the array’scountproperty. Except whencountis0(meaning the array is empty), the largest valid index in an array will always becount - 1, because arrays are indexed from zero.

如果我们试着对索引越界的数据进行检索或者设置新值的操作,会引发一个运行期错误。我们可以使用索引值和数组的count属性进行比较来在使用某个索引之前先检验是否有效。除了当count等于 0 时(说明这是个空数组),最大索引值一直是count - 1,因为数组都是零起索引。

Any gaps in an array are closed when an item is removed, and so the value at index0is once again equal to"Six eggs":

数据项被移除后数组中的空出项会被自动填补,所以现在索引值为0的数据项的值再次等于"Six eggs":

firstItem=shoppingList[0]

// firstItem is now equal to "Six eggs"

If you want to remove the final item from an array, use theremoveLast()method rather than theremove(at:)method to avoid the need to query the array’scountproperty. Like theremove(at:)method,removeLast()returns the removed item:

如果我们只想把数组中的最后一项移除,可以使用removeLast()方法而不是remove(at:)方法来避免我们需要获取数组的count属性。就像后者一样,前者也会返回被移除的数据项:

let apples=shoppingList.removeLast()

// the last item in the array has just been removed

// shoppingList now contains 5 items, and no apples

// shoppingList 现在只有5项,不包括 Apples

// the apples constant is now equal to the removed "Apples" string

// apples 常量的值现在等于 "Apples" 字符串

Iterating Over an Array (数组的遍历)

You can iterate over the entire set of values in an array with thefor-inloop:

我们可以使用for-in循环来遍历所有数组中的数据项:

for item in shoppingList{

    print(item)

}

// Six eggs

// Milk

// Flour

// Baking Powder

// Bananas

If you need the integer index of each item as well as its value, use theenumerated()method to iterate over the array instead. For each item in the array, theenumerated()method returns a tuple composed of an integer and the item. The integers start at zero and count up by one for each item; if you enumerate over a whole array, these integers match the items’ indices. You can decompose the tuple into temporary constants or variables as part of the iteration:

如果我们同时需要每个数据项的值和索引值,可以使用enumerated()方法来进行数组遍历。enumerated()返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历:

for (index,value) in shoppingList.enumerated() {

    print("Item\(index+1):\(value)")

}

// Item 1: Six eggs

// Item 2: Milk

// Item 3: Flour

// Item 4: Baking Powder

// Item 5: Bananas

For more about thefor-inloop, seeFor-In Loops.

更多关于for-in循环的介绍请参见for 循环

Sets (集合)

Asetstores distinct values of the same type in a collection with no defined ordering. You can use a set instead of an array when the order of items is not important, or when you need to ensure that an item only appears once.

集合(Set)用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。

Note

Swift’sSettype is bridged to Foundation’sNSSetclass. For more information about usingSetwith Foundation and Cocoa, seeWorking with Cocoa Data TypesinUsing Swift with Cocoa and Objective-C (Swift 3.0.1).

Swift的Set类型被桥接到Foundation中的NSSet类。关于使用Foundation和Cocoa中Set的知识,参见Using Swift with Cocoa and Obejective-C(Swift 3.0.1)使用 Cocoa 数据类型部分。

Hash Values for Set Types (集合类型的哈希值)

A type must behashablein order to be stored in a set—that is, the type must provide a way to compute ahash valuefor itself. A hash value is anIntvalue that is the same for all objects that compare equally, such that ifa == b, it follows thata.hashValue == b.hashValue.

一个类型为了存储在集合中,该类型必须是可哈希化的--也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是Int类型的,相等的对象哈希值必须相同,比如a==b,因此必须a.hashValue == b.hashValue。

All of Swift’s basic types (such asString,Int,Double, andBool) are hashable by default, and can be used as set value types or dictionary key types. Enumeration case values without associated values (as described inEnumerations) are also hashable by default.

Swift 的所有基本类型(比如String,Int,Double和Bool)默认都是可哈希化的,可以作为集合的值的类型或者字典的键的类型。没有关联值的枚举成员值(在枚举有讲述)默认也是可哈希化的。

Note

You can use your own custom types as set value types or dictionary key types by making them conform to theHashableprotocol from Swift’s standard library. Types that conform to theHashableprotocol must provide a gettableIntproperty calledhashValue. The value returned by a type’shashValueproperty is not required to be the same across different executions of the same program, or in different programs.

Because theHashableprotocol conforms toEquatable, conforming types must also provide an implementation of the equals operator (==). TheEquatableprotocol requires any conforming implementation of==to be an equivalence relation. That is, an implementation of==must satisfy the following three conditions, for all valuesa,b, andc:

a == a(Reflexivity)

a == bimpliesb == a(Symmetry)

a == b && b == cimpliesa == c(Transitivity)

For more information about conforming to protocols, seeProtocols.

你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型符合 Swift 标准库中的Hashable协议。符合Hashable协议的类型需要提供一个类型为Int的可读属性hashValue。由类型的hashValue属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。

因为Hashable协议符合Equatable协议,所以遵循该协议的类型也必须提供一个"是否相等"运算符(==)的实现。这个Equatable协议要求任何符合==实现的实例间都是一种相等的关系。也就是说,对于a,b,c三个值来说,==的实现必须满足下面三种情况:

a == a(自反性)

a == b意味着b == a(对称性)

a == b && b == c意味着a == c(传递性)

关于遵循协议的更多信息,请看协议

Set Type Syntax (集合类型语法)

The type of a Swift set is written asSet, whereElementis the type that the set is allowed to store. Unlike arrays, sets do not have an equivalent shorthand form.

Swift 中的Set类型被写为Set,这里的Element表示Set中允许存储的类型,和数组不同的是,集合没有等价的简化形式。

Creating and Initializing an Empty Set (创建并且初始化一个空的集合)

You can create an empty set of a certain type using initializer syntax:

你可以通过构造器语法创建一个特定类型的空集合:

var letters=Set()

print("letters is of type Set with\(letters.count)items.")

// Prints "letters is of type Set with 0 items."

Note

The type of thelettersvariable is inferred to beSet, from the type of the initializer.

通过构造器,这里的letters变量的类型被推断为Set。

Alternatively, if the context already provides type information, such as a function argument or an already typed variable or constant, you can create an empty set with an empty array literal:

此外,如果上下文提供了类型信息,比如作为函数的参数或者已知类型的变量或常量,我们可以通过一个空的数组字面量创建一个空的Set:

letters.insert("a")

// letters now contains 1 value of type Character

letters= []

// letters is now an empty set, but is still of type Set

Creating a Set with an Array Literal (用数组字面量创建集合)

You can also initialize a set with an array literal, as a shorthand way to write one or more values as a set collection.

你可以使用数组字面量来构造集合,并且可以使用简化形式写一个或者多个值作为集合元素。

The example below creates a set calledfavoriteGenresto storeStringvalues:

下面的例子创建一个称之为favoriteGenres的集合来存储String类型的值:

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

// favoriteGenres has been initialized with three initial items

ThefavoriteGenresvariable is declared as “a set ofStringvalues”, written asSet. Because this particular set has specified a value type ofString, it isonlyallowed to storeStringvalues. Here, thefavoriteGenresset is initialized with threeStringvalues ("Rock","Classical", and"Hip hop"), written within an array literal.

这个favoriteGenres变量被声明为“一个String值的集合”,写为Set。由于这个特定的集合含有指定String类型的值,所以它只允许存储String类型值。这里的favoriteGenres变量有三个String类型的初始值("Rock","Classical"和"Hip hop"),并以数组字面量的方式出现。

Note

ThefavoriteGenresset is declared as a variable (with thevarintroducer) and not a constant (with theletintroducer) because items are added and removed in the examples below.

favoriteGenres被声明为一个变量(拥有var标示符)而不是一个常量(拥有let标示符),因为它里面的元素将会在下面的例子中被增加或者移除。

A set type cannot be inferred from an array literal alone, so the typeSetmust be explicitly declared. However, because of Swift’s type inference, you don’t have to write the type of the set if you’re initializing it with an array literal containing values of the same type. The initialization offavoriteGenrescould have been written in a shorter form instead:

一个Set类型不能从数组字面量中被单独推断出来,因此Set类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个Set并且该数组字面量中的所有元素类型相同,那么你无须写出Set的具体类型。favoriteGenres的构造形式可以采用简化的方式代替:

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

Because all values in the array literal are of the same type, Swift can infer thatSetis the correct type to use for thefavoriteGenresvariable.

由于数组字面量中的所有元素类型相同,Swift 可以推断出Set作为favoriteGenres变量的正确类型。

Accessing and Modifying a Set (访问和修改一个集合)

You access and modify a set through its methods and properties.

你可以通过Set的属性和方法来访问和修改一个Set。

To find out the number of items in a set, check its read-onlycountproperty:

为了找出一个Set中元素的数量,可以使用其只读属性count:

print("I have\(favoriteGenres.count)favorite music genres.")

// Prints "I have 3 favorite music genres."

Use the BooleanisEmptyproperty as a shortcut for checking whether thecountproperty is equal to0:

使用布尔属性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."

You can add a new item into a set by calling the set’sinsert(_:)method:

你可以通过调用Set的insert(_:)方法来添加一个新元素:

favoriteGenres.insert("Jazz")

// favoriteGenres now contains 4 items

You can remove an item from a set by calling the set’sremove(_:)method, which removes the item if it’s a member of the set, and returns the removed value, or returnsnilif the set did not contain it. Alternatively, all items in a set can be removed with itsremoveAll()method.

你可以通过调用Set的remove(_:)方法去删除一个元素,如果该值是该Set的一个元素则删除该元素并且返回被删除的元素值,否则如果该Set不包含该值,则返回nil。另外,Set中的所有元素可以通过它的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."

To check whether a set contains a particular item, use thecontains(_:)method.

使用contains(_:)方法去检查Set中是否包含一个特定的值:

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

Iterating Over a Set (遍历一个集合)

You can iterate over the values in a set with afor-inloop.

你可以在一个for-in循环中遍历一个Set中的所有值。

for genre in favoriteGenres{

    print("\(genre)")

}

// Jazz

// Hip hop

// Classical

For more about thefor-inloop, seeFor-In Loops.

更多关于for-in循环的信息,参见For 循环

Swift’sSettype does not have a defined ordering. To iterate over the values of a set in a specific order, use thesorted()method, which returns the set’s elements as an array sorted using the

Swift 的Set类型没有确定的顺序,为了按照特定顺序来遍历一个Set中的值可以使用sorted()方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定.

for genre in favoriteGenres.sorted() {

    print("\(genre)")

}

// Classical

// Hip hop

// Jazz

Performing Set Operations (集合操作)

You can efficiently perform fundamental set operations, such as combining two sets together, determining which values two sets have in common, or determining whether two sets contain all, some, or none of the same values.

你可以高效地完成Set的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。

Fundamental Set Operations (基本集合操作)

The illustration below depicts two sets—aandb—with the results of various set operations represented by the shaded regions.

下面的插图描述了两个集合-a和b-以及通过阴影部分的区域显示集合各种操作的结果。



1. Use theintersection(_:)method to create a new set with only the values common to both sets.

使用intersection(_:)方法根据两个集合中都包含的值创建的一个新的集合。

2. Use thesymmetricDifference(_:)method to create a new set with values in either set, but not both.

使用symmetricDifference(_:)方法根据在一个集合中但不在两个集合中的值创建一个新的集合。

3. Use theunion(_:)method to create a new set with all of the values in both sets.

使用union(_:)方法根据两个集合的值创建一个新的集合。

4. Use thesubtracting(_:)method to create a new set with values not in the specified set.

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

Set Membership and Equality (集合的成员关系相等)

The illustration below depicts three sets—a,bandc—with overlapping regions representing elements shared among sets. Setais asupersetof setb, becauseacontains all elements inb. Conversely, setbis asubsetof seta, because all elements inbare also contained bya. Setband setcaredisjointwith one another, because they share no elements in common.

下面的插图描述了三个集合-a,b和c,以及通过重叠区域表述集合间共享的元素。集合a是集合b的父集合,因为a包含了b中所有的元素,相反的,集合b是集合a的子集合,因为属于b的元素也被a包含。集合b和集合c彼此不关联,因为它们之间没有共同的元素。



1. Use the “is equal” operator (==) to determine whether two sets contain all of the same values.

使用“是否相等”运算符(==)来判断两个集合是否包含全部相同的值。

2. Use theisSubset(of:)method to determine whether all of the values of a set are contained in the specified set.

使用isSubset(of:)方法来判断一个集合中的值是否也被包含在另外一个集合中。

3. Use theisSuperset(of:)method to determine whether a set contains all of the values in a specified set.

使用isSuperset(of:)方法来判断一个集合中包含另一个集合中所有的值。

4. Use theisStrictSubset(of:)orisStrictSuperset(of:)methods to determine whether a set is a subset or superset, but not equal to, a specified set.

使用isStrictSubset(of:)或者isStrictSuperset(of:)方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。

5. Use theisDisjoint(with:)method to determine whether two sets have any values in common.

使用isDisjoint(with:)方法来判断两个集合是否不含有相同的值(是否没有交集)。

let houseAnimals:Set= ["🐶","🐱"]

let farmAnimals:Set= ["🐮","🐔","🐑","🐶","🐱"]

let cityAnimals:Set= ["🐦","🐭"]

houseAnimals.isSubset(of:farmAnimals)

// true

farmAnimals.isSuperset(of:houseAnimals)

// true

farmAnimals.isDisjoint(with:cityAnimals)

// true

Dictionaries (字典)

Adictionarystores associations between keys of the same type and values of the same type in a collection with no defined ordering. Each value is associated with a uniquekey, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word.

字典是一种存储多个相同类型的值的容器。每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。

Note

Swift’sDictionarytype is bridged to Foundation’sNSDictionaryclass. For more information about usingDictionarywith Foundation and Cocoa, seeWorking with Cocoa Data TypesinUsing Swift with Cocoa and Objective-C (Swift 3.0.1).

Swift 的Dictionary类型被桥接到Foundation的NSDictionary类。更多关于在Foundation和Cocoa中使用Dictionary类型的信息,参见Using Swift with Cocoa and Obejective-C(Swift 3.0.1)使用 Cocoa 数据类型部分。

Dictionary Type Shorthand Syntax (字典类型的简化语法)

The type of a Swift dictionary is written in full asDictionary, whereKeyis the type of value that can be used as a dictionary key, andValueis the type of value that the dictionary stores for those keys.

Swift 的字典使用Dictionary定义,其中Key是字典中键的数据类型,Value是字典中对应于这些键所存储值的数据类型。

Note

A dictionaryKeytype must conform to theHashableprotocol, like a set’s value type.

一个字典的Key类型必须遵循Hashable协议,就像Set的值类型。

You can also write the type of a dictionary in shorthand form as[Key: Value]. Although the two forms are functionally identical, the shorthand form is preferred and is used throughout this guide when referring to the type of a dictionary.

我们也可以用[Key: Value]这样简化的形式去创建一个字典类型。虽然这两种形式功能上相同,但是后者是首选,并且这本指导书涉及到字典类型时通篇采用后者。

Creating an Empty Dictionary (创建一个空的字典)

As with arrays, you can create an emptyDictionaryof a certain type by using initializer syntax:

我们可以像数组一样使用构造语法创建一个拥有确定类型的空字典:

var namesOfIntegers= [Int:String]()

// namesOfIntegers is an empty [Int: String] dictionary

This example creates an empty dictionary of type[Int: String]to store human-readable names of integer values. Its keys are of typeInt, and its values are of typeString.

这个例子创建了一个[Int: String]类型的空字典来储存整数的英语命名。它的键是Int型,值是String型。

If the context already provides type information, you can create an empty dictionary with an empty dictionary literal, which is written as[:](a colon inside a pair of square brackets):

如果上下文已经提供了类型信息,我们可以使用空字典字面量来创建一个空字典,记作[:](中括号中放一个冒号):

namesOfIntegers[16] ="sixteen"

// namesOfIntegers now contains 1 key-value pair

namesOfIntegers= [:]

// namesOfIntegers is once again an empty dictionary of type [Int: String]

Creating a Dictionary with a Dictionary Literal (用字典字面量创建字典)

You can also initialize a dictionary with adictionary literal, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as aDictionarycollection.

我们可以使用字典字面量来构造字典,这和我们刚才介绍过的数组字面量拥有相似语法。字典字面量是一种将一个或多个键值对写作Dictionary集合的快捷途径。

Akey-value pairis a combination of a key and a value. In a dictionary literal, the key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets:

一个键值对是一个key和一个value的结合体。在字典字面量中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含、由逗号分割:

[key 1:value 1,key 2:value 2,key 3:value 3]

The example below creates a dictionary to store the names of international airports. In this dictionary, the keys are three-letter International Air Transport Association codes, and the values are airport names:

下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称:

var airports: [String:String] = ["YYZ":"Toronto Pearson","DUB":"Dublin"]

The airportsdictionary is declared as having a type of[String: String], which means “aDictionarywhose keys are of typeString, and whose values are also of typeString”.

airports字典被声明为一种[String: String]类型,这意味着这个字典的键和值都是String类型。

Note

Theairportsdictionary is declared as a variable (with thevarintroducer), and not a constant (with theletintroducer), because more airports are added to the dictionary in the examples below.

airports字典被声明为变量(用var关键字)而不是常量(let关键字)因为后来更多的机场信息会被添加到这个示例字典中。

Theairportsdictionary is initialized with a dictionary literal containing two key-value pairs. The first pair has a key of"YYZ"and a value of"Toronto Pearson". The second pair has a key of"DUB"and a value of"Dublin".

airports字典使用字典字面量初始化,包含两个键值对。第一对的键是YYZ,值是Toronto Pearson。第二对的键是DUB,值是Dublin。

This dictionary literal contains twoString: Stringpairs. This key-value type matches the type of theairportsvariable declaration (a dictionary with onlyStringkeys, and onlyStringvalues), and so the assignment of the dictionary literal is permitted as a way to initialize theairportsdictionary with two initial items.

这个字典语句包含了两个String: String类型的键值对。它们对应airports变量声明的类型(一个只有String键和String值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的airport字典。

As with arrays, you don’t have to write the type of the dictionary if you’re initializing it with a dictionary literal whose keys and values have consistent types. The initialization ofairportscould have been written in a shorter form instead:

和数组一样,我们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型。airports字典也可以用这种简短方式定义:

var airports= ["YYZ":"Toronto Pearson","DUB":"Dublin"]

Because all keys in the literal are of the same type as each other, and likewise all values are of the same type as each other, Swift can infer that[String: String]is the correct type to use for theairportsdictionary.

因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出Dictionary是airports字典的正确类型。

Accessing and Modifying a Dictionary (访问和修改字典)

You access and modify a dictionary through its methods and properties, or by using subscript syntax.

我们可以通过字典的方法和属性来访问和修改字典,或者通过使用下标语法。

As with an array, you find out the number of items in aDictionaryby checking its read-onlycountproperty:

和数组一样,我们可以通过字典的只读属性count来获取某个字典的数据项数量:

print("The airports dictionary contains\(airports.count)items.")

// Prints "The airports dictionary contains 2 items."

Use the BooleanisEmptyproperty as a shortcut for checking whether thecountproperty is equal to0:

使用布尔属性isEmpty作为一个缩写形式去检查count属性是否为0:

if airports.isEmpty{

    print("The airports dictionary is empty.")

}else{

    print("The airports dictionary is not empty.")

}

// Prints "The airports dictionary is not empty."

You can add a new item to a dictionary with subscript syntax. Use a new key of the appropriate type as the subscript index, and assign a new value of the appropriate type:

我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个恰当类型的键作为下标索引,并且分配恰当类型的新值:

airports["LHR"] ="London"

// the airports dictionary now contains 3 items

You can also use subscript syntax to change the value associated with a particular key:

我们也可以使用下标语法来改变特定键对应的值:

airports["LHR"] ="London Heathrow"

// the value for "LHR" has been changed to "London Heathrow"

As an alternative to subscripting, use a dictionary’supdateValue(_:forKey:)method to set or update the value for a particular key. Like the subscript examples above, theupdateValue(_:forKey:)method sets a value for a key if none exists, or updates the value if that key already exists. Unlike a subscript, however, theupdateValue(_:forKey:)method returns theoldvalue after performing an update. This enables you to check whether or not an update took place.

作为另一种下标方法,字典的updateValue(_:forKey:)方法可以设置或者更新特定键对应的值。就像上面所示的下标示例,updateValue(_:forKey:)方法在这个键不存在对应值的时候会设置新值或者在存在时更新已存在的值。和上面的下标方法不同的,updateValue(_:forKey:)这个方法返回更新值之前的原值。这样使得我们可以检查更新是否成功。

TheupdateValue(_:forKey:)method returns an optional value of the dictionary’s value type. For a dictionary that storesStringvalues, for example, the method returns a value of typeString?, or “optionalString”. This optional value contains the old value for that key if one existed before the update, or nil if no value existed:

updateValue(_:forKey:)方法会返回对应值的类型的可选值。举例来说:对于存储String值的字典,这个函数会返回一个String?或者“可选String”类型的值。如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是nil。

if let oldValue=airports.updateValue("Dublin Airport",forKey:"DUB") {

    print("The old value for DUB was\(oldValue).")

}

// Prints "The old value for DUB was Dublin."

You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returnsnil:

我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值的类型的可选值。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选值,否则将返回nil:

if let airportName=airports["DUB"] {

    print("The name of the airport is\(airportName).")

}else{

    print("That airport is not in the airports dictionary.")

}

// Prints "The name of the airport is Dublin Airport."

You can use subscript syntax to remove a key-value pair from a dictionary by assigning a value ofnilfor that key:

我们还可以使用下标语法来通过给某个键的对应值赋值为nil来从字典里移除一个键值对:

airports["APL"] ="Apple International"

// "Apple International" is not the real airport for APL, so delete it

airports["APL"] =nil

// APL has now been removed from the dictionary

Alternatively, remove a key-value pair from a dictionary with theremoveValue(forKey:)method. This method removes the key-value pair if it exists and returns the removed value, or returnsnilif no value existed:

此外,removeValue(forKey:)方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回nil:

if let removedValue=airports.removeValue(forKey:"DUB") {

    print("The removed airport's name is\(removedValue).")

}else{

    print("The airports dictionary does not contain a value for DUB.")

}

// Prints "The removed airport's name is Dublin Airport."

Iterating Over a Dictionary (字典遍历)

You can iterate over the key-value pairs in a dictionary with afor-inloop. Each item in the dictionary is returned as a(key, value)tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration:

我们可以使用for-in循环来遍历某个字典中的键值对。每一个字典中的数据项都以(key, value)元组形式返回,并且我们可以使用临时常量或者变量来分解这些元组:

for (airportCode,airportName) in airports {

    print("\(airportCode):\(airportName)")

}

// YYZ: Toronto Pearson

// LHR: London Heathrow

For more about thefor-inloop, seeFor-In Loops.

更多关于for-in循环的信息,参见For 循环

You can also retrieve an iterable collection of a dictionary’s keys or values by accessing itskeysandvaluesproperties:

通过访问keys或者values属性,我们也可以遍历字典的键或者值:

for airportCodeinairports.keys {

    print("Airport code:\(airportCode)")

}

// Airport code: YYZ

// Airport code: LHR

forairportNameinairports.values{

print("Airport name:\(airportName)")

}

// Airport name: Toronto Pearson

// Airport name: London Heathrow

If you need to use a dictionary’s keys or values with an API that takes anArrayinstance, initialize a new array with thekeysorvaluesproperty:

如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受Array实例的 API 的参数,可以直接使用keys或者values属性构造一个新数组:

let airportCodes= [String](airports.keys)

// airportCodes is ["YYZ", "LHR"]

let airportNames= [String](airports.values)

// airportNames is ["Toronto Pearson", "London Heathrow"]

Swift’sDictionarytype does not have a defined ordering. To iterate over the keys or values of a dictionary in a specific order, use thesorted()method on itskeysorvaluesproperty.

Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的keys或values属性使用sorted()方法。

推荐阅读更多精彩内容