Swift学习笔记六

集合类型(Collection Type)

Swift提供三种主要的集合类型:数组(array)、集合(set)、字典(dictionary)。数组是有序的值序列,集合是无序的值序列,字典是无序的键值对序列。这三个类型都要求显示指定存储值的类型。因此不能把不同类型的值增加到它们中。

如果创建的集合类型并赋值给一个变量而非常量,那么它就是可以改变的。如果是赋值给一个常量,那么它就是不可改变的。这和OC中是有区别的,OC是在创建的时候就需要用不同的类来创建实例来确定是否可变。尽管如此,在确定该变量应该不可改变或者不会改变的时候,尽量赋值给常量使它不可改变。

Swift中的array,set,dictionary都是被实现为通用集合(generic collection)的。通用(generi)是Swift的一个特性,通用代码允许用户创建灵活可重用的函数或者类型,它可以避免重复开发,比如你可以创建一个数组,它可以包含Int类型,或者是String,或者是其他类型,你不需要在一开始就特别制定它的类型。generi特性在后面会专门介绍。

数组

数组是用来有序存储一系列同类型的值的数据类型。Swift的array是和Foundation的NSArray相通的。数组中的元素可以是重复的。

数组类型简写

Swift的数组类型全写是Array<SomeType>,也可以将数组的类型简写为[SomeType]。尽管两种方式是相通的,但是简写方式是被推荐的。

可以用初始化语法创建一个指定类型的空数组:

var someInts = [Int]()
println("someInts is of type [Int] with \(someInts.count) items.")
// prints "someInts is of type [Int] with 0 items.”

注意someInts的类型就通过初始化器设定为了Int。

同时,如果上下文已经明确了它的数据类型,比如函数传递的参数或者是已经确定类型的变量/常量,此时可以用空数组字面量来创建空数组,而无需指明类型,接上个例子:

someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type [Int]

Swift的数组也提供另一个初始化器,可以用来创建指定长度的数组,数组的元素都初始化为给定的默认值。通过向初始化器传递长度和默认值两个参数来创建,如下:

var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]

可以用+号将两个已经存在的并且类型合适的数组连接起来从而创建一个新数组。接上一个例子:

var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as [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]

也可以通过数组字面量来创建一个新数组,比如:

var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items

注意这里的变量类型写法,表示shoppingList是一个存储String的数组。

你可能还没忘记前面介绍到的Swift的类型侦测,这里你如果是用数组字面量来创建数组,根据你给出的元素,编译器就能够推断出数据类型了,你不需要显示地指定数组类型,比如:

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

操作数组

可以通过下标语法或者属性方法来操作数组。

count只读属性给出数组当前的长度。

isEmpty属性是布尔值,其实就是检查count是否为0的简写。

append(_:)方法用来向变量数组追加元素,当然,也可以用+=的方式来向数组追加元素。

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

同其他语言一样,可以通过下标语法来检索数组元素,这里一点特殊的是,Swift中,下标语法允许指定一个范围,而不仅仅是一个值,比如:

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

注意这里,指定的范围其实是三个,而传入的数组只有两个元素,这是允许的,这时数组shoppingList含有6个元素而非7个,原有数组的4 5 6位的元素被替换为了"Bananas"  "Apples"两个元素。

注意:不能通过下标语法来给数组末尾追加元素。

insert(_:atIndex:)用来向数组的指定位置插入一个元素:

shoppingList.insert("Maple Syrup", atIndex: 0)
// shoppingList now contains 7 items
// "Maple Syrup" is now the first item in the list

removeAtIndex(_:)用来删除指定位置的一个元素,并将它返回:

let mapleSyrup = shoppingList.removeAtIndex(0)
// the item that was at index 0 has just been removed
// shoppingList now contains 6 items, and no Maple Syrup
// the mapleSyrup constant is now equal to the removed "Maple Syrup" string”

显而易见地,此方法要求传入的参数必须在数组的范围内,如果超出范围则会触发运行时错误。删除一个元素后,其他元素会改变位置来填补空白,数组长度也就发生了变化。

removeLast()方法用来删除数组的最后一个元素并将其返回。

遍历数组

用for-in遍历数组

for item in shoppingList {
    println(item)
}

如果你同时需要获得索引序号和值,用全局的枚举函数enumerate在数组上循环,全局枚举函数返回一个元组,它由数组中每个元素的序号和值复合组成。然后在这个元组上用for in将其分解。

for (index, value) in enumerate(shoppingList) {
    println("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas

集合(Set)

Set用来无序存储一些列相同类型的不同值的元素。当存储元素的顺序并不重要或者为了确保序列中的元素只会出现一次的时候,可以用set取代array。Swift的Set和Foundation中的NSSet是相通的。

Set的数据类型语法是Set<SomeType>,Set并不支持类型语法的简写,这是唯一的方式。

通过初始化器来创建空的Set:

var letters = Set<Character>()
println("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>

用数组字面量也可以创建含有元素的集合,这可以当做初始化集合的简写形式:

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

当然,通过数组字面量的形式时,编译器可以推断出数据类型,因此可以省略掉类型。

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

操作集合

可以通过属性和方法来操作集合。

count只读属性返回集合的元素个数。

isEmpty属性是布尔值,可以当做判断count是否为0的简写。

insert(_:)用于向集合中插入一个元素。

remove(_:)用于从集合中删除一个元素,如果集合包含这个元素,则将其删除,并返回这个元素,如果集合不包含这个元素,则返回nil。

removeAll()删除集合中所有元素。

contains(_:)用于检查集合是否包含指定元素,返回一个布尔值。

遍历集合

像数组一样,用for-in来遍历集合。

因为Set并不是按序存储元素的,要按一定顺序遍历Set里的元素,用全局函数sorted,它返回一个按指定顺序排列好的集合:

for genre in sorted(favoriteGenres) {
    println("\(genre)")
}
// prints "Classical"
// prints "Hip hop"
// prints "Jazz”

集合运算

【构建集合】

集合可以快速进行一系列复杂运算,比如合并、获取交集、并集等。

union(_:)返回两个集合并集

intersect(_:)返回两个集合交集

subtract(_:)返回属于第一个集合且不属于第二个集合的元素集

exclusiveOr(_:)返回两个集合各自拥有的不同的元素集,即intersect(_:)的补集

let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
sorted(oddDigits.union(evenDigits))
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sorted(oddDigits.intersect(evenDigits))
// []
sorted(oddDigits.subtract(singleDigitPrimeNumbers))
// [1, 9]
sorted(oddDigits.exclusiveOr(singleDigitPrimeNumbers))
// [1, 2, 9]

【集合比较】

==用于判断两个集合是否包含完全相同的元素

isSubsetOf(_:)判断是否一个集合的所有元素都被包含在另一个元素中

isSupersetOf(_:)判断是否一个集合包含了另一个集合的所有元素

isStrictSubsetOf(_:)和isStrictSupersetOf(_:)与上述两个方法类似,不过它们确保两个集合在满足条件的同时且不相等

isDisjointWith(_:)判断两个集合是否包含相同的元素,如果存在则返回false

let houseAnimals: Set = ["??", "??"]
let farmAnimals: Set = ["??", "??", "??", "??", "??"]
let cityAnimals: Set = ["??", "??"]
houseAnimals.isSubsetOf(farmAnimals)
// true
farmAnimals.isSuperSetOf(houseAnimals)
// true
farmAnimals.isDisjointWith(cityAnimals)
// true

集合类型的哈希值

为了被存储在集合中,数据类型必须是可散列的(hashable),就是说,这个数据类型必须提供一种方式为它本身计算它的散列值(hash value)。散列值是一个Int值,任何两个对象只有被判断为相等,那么它们的散列值就是相等的。

Swift的所有基础类型(String,Int,Double和bool等)都是默认可序列化的。因此可以被作为集合类型或者字典键类型。

注意:当你创建自定义数据类型的时候,可以使它们遵守Swift标准库里的Hashable协议,这样就可以作为集合类型或者字典键类型了。遵守Hashable协议的类型必须提供一个可获取的Int类型属性:hashValue,这个属性的返回值在同一断程序的多次执行之间或者不同的程序之间并不要求都一样。因为Hashable协议又遵守Equatable协议,因此自定义类型必须同时实现"是否相等(is equal)"操作(==)。Equatable协议要求是否相等操作的实现必须遵守相等关系的约束,即对于任意值a b c,是否相等的实现应该满足如下三个条件:

a == a (Reflexivity) //自反性
a == b implies b == a (Symmetry) //对称性
a == b && b == c implies a == c (Transitivity) //传递性

字典类型

字典类型用来存储同类型键和同类型值的对应关系的无序序列。每个值(value)都对应一个唯一的键(key),作为该值在字典里的唯一标识符。Swift的字典和Foundation的NSDictionary是相通的。

字典类型的语法是Dictionary<Key,Value>。(其中Key必须是可散列的),这种语法形式也可以简写为[Key:Value],这两种语法形式是等价的,不过简写形式是被推荐的。

可以用初始化器创建一个空的字典:

var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary

如果上下文已经提供了类型信息了,也可以用简写形式省略类型声明,直接用[:]:

namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]

字典字面量

字典字面量和数组字面量比较类似,比如:

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

当然,结合Swift的类型侦测特性,在用字面量形式初始化字典的时候,也可以不写类型声明:

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

操作字典

操作字典是通过字典的一些属性和方法,或者是下标属性实现。

count只读属性,返回字典中的键值对个数

isEmpty属性与前文所述类似

直接通过下标语法来给字典添加新元素或者更改已有元素:

airports["LHR"] = "London"

updateValue(_:forKey:)可以代替下标语法来实现添加新元素或更改已有元素。与下标语法不同的是,这个方法如果成功更新了旧的元素,则会返回旧的元素,这样可以确认是否有一个成功的更新发生了,因此,这个方法返回的其实是一个与字典元素值类型对应的可选类型(Optional Type),比如,字典元素值是String类型,则该方法返回的是String?类型,如果成功更新了一个元素值,则返回该值,如果没有(比如那个键对应的值本身不存在字典里),则返回nil。

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    println("The old value for DUB was \(oldValue).")
}
// prints "The old value for DUB was Dublin.”

可以用下标语法从字典获取指定key对应的值。这是因为字典的下标语法其实返回的是可选类型,如果该键对应的值存在,就返回该值,如果不存在,就返回nil。

if let airportName = airports["DUB"] {
    println("The name of the airport is \(airportName).")
} else {
    println("That airport is not in the airports dictionary.")
}
// prints "The name of the airport is Dublin Airport.”

可以通过下标语法将某个键对应的值设为nil来删除这个键值对。

removeValueForKey(_:)方法也可以用来实现删除字典中特定键值对,如果键值对存在,则删除之并返回被删除的值,如果不存在,则返回nil。

遍历字典

可以用for-in来遍历字典,字典中的每个元素将以(key,value)元组返回:

for (airportCode, airportName) in airports {
    println("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow

也可以通过在keys或者values属性上执行循环,来遍历字典中的所有键或者值:

for airportCode in airports.keys {
    println("Airport code: \(airportCode)")
}
// Airport code: YYZ
// Airport code: LHR

for airportName in airports.values {
    println("Airport name: \(airportName)")
}
// Airport name: Toronto Pearson
// Airport name: London Heathrow

如果需要用Array的一些API来处理字典的所有键或者所有值,可以用keys或values属性来初始化创建一个数组:

let airportCodes = [String](airports.keys)
// airportCodes is ["YYZ", "LHR"]

let airportNames = [String](airports.values)
// airportNames is ["Toronto Pearson", "London Heathrow"]

字典本身是无序存储的,如果需要按某个顺序,可以在keys或者values上使用全局函数sort来排定某个顺序。

时间: 2024-10-10 22:06:23

Swift学习笔记六的相关文章

swift学习笔记(六)析构过程和使用闭包对属性进行默认值赋值

一.通过闭包和函数实现属性的默认值 当某个存储属性的默认值需要定制时,可以通过闭包或全局函数来为其提供定制的默认值. 注:全局函数结构体和枚举使用关键字static标注    函数则使用class关键字标注 当对一个属性使用闭包函数进行赋值时,每当此属性所述的类型被创建实例时,对应的闭包或函数会被调用,而他们的返回值会被作为属性的默认值. ESC: Class SomeCLass{ let someProperty:SomeType={ //给someProperty赋一个默认值 //返回一个与

初探swift语言的学习笔记六(ARC-自动引用计数,内存管理)

Swift使用自动引用计数(ARC)来管理应用程序的内存使用.这表示内存管理已经是Swift的一部分,在大多数情况下,你并不需要考虑内存的管理.当实例并不再被需要时,ARC会自动释放这些实例所使用的内存. 另外需要注意的: 引用计数仅仅作用于类实例上.结构和枚举是值类型,而非引用类型,所以不能被引用存储和传递. swift的ARC工作过程 每当创建一个类的实例,ARC分配一个内存块来存储这个实例的信息,包含了类型信息和实例的属性值信息. 另外当实例不再被使用时,ARC会释放实例所占用的内存,这些

Swift学习笔记(一):基础

一.常量 & 变量 //常量 let constantsTeam = 1 //变量 var variablesTeam = 2 尽可能使用常量,这样更清晰并且内存更不容易肾亏. 二.显示/隐式指定类型 //隐式 let inferredTeam = 3 //显式 let explicitTeam:Int = 4 三.字符串输出 //通过\(变量或常量名)来引用组合字符串 println("\(inferredTeam) is bigger than \(variablesTeam)!&q

Swift学习笔记:类和结构

一.类和结构的异同 类和结构有一些相似的地方,它们都可以: 1. 定义一些可以赋值的属性: 2. 定义具有功能性的方法 3. 定义下标,使用下标语法 4. 定义初始化方法来设置初始状态 5. 在原实现方法上的可扩展性 根据协议提供某一特定类别的基本功能 1. 类还有一些结构不具备的特性: 2. 类的继承性 3. 对类实例实时的类型转换 4. 析构一个类的实例使之释放空间 5. 引用计数,一个类实例可以有多个引用 1. 定义语法 struct Name{ let firstName = "&quo

python之raw_input()(学习笔记六)

python之raw_input()(学习笔记六) 我们经常使用raw_input()读取用户的输入,如下例子所示: >>> name = raw_input('please input your name:'),截图如下: 下面简单说下,raw_input()与if搭配使用,脚本如下: #!/usr/bin/env python # -*- coding:utf-8 -*- birth = raw_input('birth:') if birth < 2000: print '0

SWIFT学习笔记05

1.Swift 无需写break,所以不会发生这种贯穿(fallthrough)的情况.2.//用不到变量名,可用"_"替换 for _ in 1...power { answer *= base } 3.case 可以匹配更多的类型模式,包括区间匹配(range matching),元组(tuple)和特定类型的描述. 可以这样用case case 1...3: naturalCount = "a few" 4.如果存在多个匹配,那么只会执行第一个被匹配到的 ca

SWIFT学习笔记02

1.//下面的这些浮点字面量都等于十进制的12.1875: let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0//==12+3*(1/16) 2.//类型别名,用typealias关键字来定义类型别名 typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min 3.//元组 let ht

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];