集合类型
Collection 类型
Collection Type
数组(Array),字典(Dictionary),集合(Set),都是以泛型结构体定义的,且不像Objective-c的mutable来表示其可进行修改,而是只有通过var声明的,才能对其进行增删改查,let声明的collection对象不仅不能改变它的值,也不能对其元素做添加,修改,删除等操作.
数组
存放相同类型的多个元素的有序线性列表,可以是任意类型,元组也可以,不允许出现不同类型的元素
数组的声明:
1.完整声明:Array<Element>,Element表示元素的类型
2.精简声明:[Element]
3.数组字面量:[value1,value2..]
//MARK:数组的声明
//完整声明
var array = Array<Int>()
//精简声明
let r = [Int]()
//5个元素,每一个都是3.0
let a = [Double](repeating:3.0,count:5)
let b = [(Int,Double)](repeating: (1,0.5), count: 3)
//数组字面量
var a1 = [1,2,3,4,5]
//数组不仅可以存放字面量,也可以存放其它常量或者变量
var a2 = [array,r,[2,3]]
//+操作符 将两个数组拼接在一起
var sumArr = a1 + [2,67,7]
sumArr
//通过下标访问操作符访问数组元素
print("first is \(sumArr[0])")
//下标不可以使用负数,当然你可以自己进行定义
//超出数组的下标范围,程序会引发异常
//Fatal error: Index out of range
//sumArr[-1]
//sumArr[20]
//下标操作符属于单目后缀操作符,它只有一个操作数。其操作数就是跟在它之前(即左侧)的后缀表达式,而下标中的表达式则不是它的操作数,这点请各位注意。此外,只有遵循了 Collection 协议的类型对象才能作为下标操作符的操作数。
//数组包含了多少个元素 Int类型的只读属性
a1.count
//判断数组是否为空,指的是是否包含元素,而不是是否为空值
r.isEmpty
a1.isEmpty
//判断数组是否包含某个元素,返回Bool类型
a1.contains(1)
a1.contains(6)
//在最后添加数组元素
a1.append(6)
//在指定的索引位置插入数组元素
a1.insert(12, at: 2)
a1
//删除数组元素(下标)
a1.remove(at: 1)
a1
//直接使用数组字面量是一个常量,无法对其进行修改
var array1 = [1,2,3,4,5]
print(array1.startIndex)
print(array1.endIndex)
if let i = array1.index(of: 30) {
print(array1[i..<array1.endIndex])
}
array1.index(after: 5)
//访问range内的数组元素
array1[1...3]
//替换range内的元素为传入的collection
array1.replaceSubrange(1..<3, with: [20,30,40,50])
print(array1)
//弹出最后一个数组元素
array1.popLast()
print(array1)
//并不改变数组的值
array = Array(array1.dropLast())
print(array1)
集合Set
集合可以存放多个相同类型的元素
1.不允许出现相同的元素
2.无序不能通过下标进行访问
3.只有遵循Hashable的类型才能作为集合的元素
String,Int,Double,Float,Bool都遵循该协议
集合的完整类型Set<Element:Hashable>,Element表示集合元素的类型,没有精简表示法
也可以通过数组字面量进行创建,但必须通过类型标注申明为Set,否则会被编译器识别为Array
//创建一个集合类型为<Int>的空集合
var setA = Set<Int>()
//或者
setA = []
//不定参构造方法
setA = Set(arrayLiteral: 1,3,4,2,1,3)
//数组字面量
var setB:Set<Int> = [1,1,2,3,4]
//集合存放对象是根据其哈希值,不是根据下标(无序),所以需要保证存放的元素类型遵循Hashable
//访问 for-in || flatMap
for item in setA {
print(item)
}
//元素的个数
setA.count
//是都包含元素
setA.isEmpty
setA.contains(1)
setA.insert(5)
setA.remove(1)
字典
以键值对的形式存放元素
特点:无序,键不允许重复,必须遵循Hashable;值可以是任意类型
完整形式Dictionary<Key:Hashable,Value>,key表示键的类型,value表示值的类型
精简表示法 [Key:Value]
//通过默认的构造方法创建一个空字典,类型为[String:Int]
var a = Dictionary<String,Int>()
//通过字典的不定参构造方法创建一个字典,使用元组来将字典的键值进行捆绑
//第一个元素为键,第二个元素为值
a = Dictionary(dictionaryLiteral: ("one",1),("two",2),("three",3))
//精简表示法
let b = [Int:Float]()
let c = [Int:Float](dictionaryLiteral: (1,1.1),(2,2.22),(3,3.333))
字典字面量
var a1:[String:Int] = [:]
a1 = ["one":1,"two":2,"three":3]
通过下标操作符进行访问,类型必须为键的类型
返回的是Optional,不存在就会返回nil
var a1 = ["one":1,"two":2,"three":3]
let four = a1["four"]
let one = a1["one"]
if let f = four {
print(f)
}else{
print("nil")
}
//根据键修改值
a1["one"] = 100
//或者根据实例方法,返回原来的值
a1.updateValue(1, forKey: "one")
//如果key存在就是修改,不存在则意味着新增
a1["four"] = 4
//根据key删除元素
a1.removeValue(forKey: "one")
//字典的个数
a1.count
//是否包含有元素
a1.isEmpty
//keys 属性的类型的是遵循 Collection 与 Equatable 协议的结构体类型;而 values 属性的类型则是遵循 MutableCollection 协议的结构体类型,它们与集合类型类似,不能通过下标方式访问其元素,而一般只能通过 for-in 循环迭代的方式逐一访问
for key in a1.keys{
print(key)
}
for value in a1.values {
print(value)
}
Range范围操作符
特点:Range 范围代表的是两个值的区间,它由上下边界进行定义,你可以通过..<来创建一个不包含上边界的半开范围,或者使用...创建同时包含上下边界的闭合范围.
应用:范围操作符可用于 for-in 循环迭代、获取一个数组的子数组、获取一个字符串的子串、case 语句中的区间匹配等场合
分别对应下面四种类型
元素满足
元素满足 (以整数为步长)
满足 | 半开范围 | 闭合范围 |
---|---|---|
Comparable | Range | ClosedRange |
Strideable | CountableRange | CountableClosedRange |
//Range,CountableRange, ClosedRange, CountableClosedRange
let emptyRange = 0.0..<0.0
let singleDigitNumbers = 0..<10
let lowercaseLetters = Character("a")...Character("z")
let numbersRange = 1...10
范围操作符的左操作数必须小于等于右操作数,否则将会导致运行时异常
对于半开区间的范围操作符,如果左操作数等于右操作数,那么该范围是一个空区间
1.只有半开范围才能表达空区间的概念 (上下边界相等)
2.只有闭合范围能够包含它的元素类型所能表达的最大值
如果ClosedRange(闭区间范围操作符)的操作数是一个整数类型,那么该范围操作符的类型将是CountableClosedRange
如果Range(半开区间范围操作符)的操作数是一个整数类型,那么该范围操作符的类型将是CountableRange
ClosedRange和Range没有遵循Sequence协议,不能用for-in循环,而CountableRange和CountableClosedRange遵循了Sequence协议,可以用for-in迭代循环
Countable Range 可数范围 只有这类范围可以被迭代,类型的stride需要用整数进行约束,所以整数和指针类型是这类范围的有效边界值,但是浮点类型不是
使用
//for-in迭代循环
//CountableRange
for i in 1..<5 {
print(i)
}
//CountableClosedRange
for y in 1...5 {
print(y)
}
//如果是浮点数可以使用选择步长的
for a in stride(from: 4, to: 5, by: 0.1) {
print(a)
}
for b in stride(from: 3, through: 5, by: 0.2){
print(b)
}
//Type 'ClosedRange<Character>' does not conform to protocol 'Sequence'
//for item in lowercaseLetters{
//
//}
//获取数组的子数组
let array = [1,2,3,4,5,6]
//[3,4,5]
print(array[2...4])
//获取字符串的子串
let string = "abcdefghigk"
let strRange = string.startIndex ..< string.endIndex
print(string[strRange])
//case区间匹配
switch 3.0 {
case 0.0 ..< 2.0:
print("in 0.0 ..< 2.0")
case 2.0 ..< 4.0:
print("in 2.0 ..< 4.0")
default:
print("No in range")
}
//[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(singleDigitNumbers.map{$0 * $0})
实例属性与方法
/// - isEmpty:是否为空
/// - contains:是否包含某个值
/// - lowerBound:表示当前范围对象的下边界,一般都是范围操作符左操作数的值。
/// - upperBound:表示当前对象的上边界。这里无论是闭区间还是半开区间,上边界的值一般都是范围操作符的右操作数的值。
/// - isEmpty:表示当前范围是否为一个空范围,如果是空范围,那么该属性的值为 true,否则为 false。对于一个闭区间范围而言,它不会存在空范围,所以这个属性必定为 false。
/// - contains(_:):判断当前范围是否包含了指定的对象。
/// - overlaps(_:):判断指定的范围是否与当前范围对象存在叠交,只要两者有交集,那么就返回 true,否则为 false
/// - clamped(to:):裁减当前的范围到指定的区间范围内。
let doubleRange = 1.0 ... 3.0
print(doubleRange.lowerBound)
print(doubleRange.upperBound)
print("0..<0是否为空\((0..<0).isEmpty)")
print("range has 2.5 :\(doubleRange.contains(2.5))")
print("是否有交集:\(doubleRange.overlaps(2.0..<4.0))")
//裁剪 必须是闭合区间
let subsRange = doubleRange.clamped(to: 0.5 ... 2.0)
/// 1.0 ... 2.0
print(subsRange)
单边范围
单边范围操作符 (partial .部分的,不完全的 ,偏向一方的)
Swift4.0提供,只对范围操作符的一端设置操作数,另一端缺省
有三种类型
- a... 后缀单目操作符,表示从操作数开始的范围,大于等于a
- ...a 前缀单目操作符,表示以操作数为终点的范围,小于等于a
- ..<a 前缀单目操作符,表示以操作数为终点的范围,但不包括该数值,即小于a
注意:操作符必须紧贴操作数
//CountablePartialRangeFrom
let countableFrom = 2...
//PartialRangeFrom
let from = 2.1...
//PartialRangeThrough
//
let throughs = ...2
//PartialRangeUpTo
let upTo = ..<2
使用:获取一个数组的子数组、获取一个字符串的子串
//使用单边范围获取数组的子数组,字符串的子串
let array = [1,2,3,4,5]
//[1,2,3]
print("...2:\(array[...2])")
//[3,4,5]
print("2..:\(array[2...])")
//[1,2]
print("..<2:\(array[..<2])")
//获取字符串后五个字符
let string = "abcdefghigk"
let strRange = string.index(string.endIndex, offsetBy: -5)...
print(string[strRange])
由于单边范围操作符不能表示一个有限范围的值,因此它不可能遵循Sequence协议,不能使用for-in
下面是一些方法
//2
countableFrom.lowerBound
//2
throughs.upperBound
//false
upTo.contains(2)