搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发

Swift | Set集合

忧郁的思想家 2020-07-01

如果你需要高效地测试某个元素是否存在于序列中并且元素的顺序不重要时,使用集合是更好的选择 (同样的操作在数组中的复杂度是 

O(n))。另外,当你需要保证序列中不出现重复元素时,也可以使用集合。



01



集合的概念




集合是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成集合的这些对象则称为该集合的元素。


集合的特性

1.确定性 :给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一。

2.互斥性 : 一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。

3.无序性 : 一个集合中,每个元素的地位都是相同的,元素之间是无序的。




02


Swift的集合


Swift的集合类型写做Set<Element>,这里的Element是Set要储存的类型。不同与数组,集合没有等价的简写。


创建集合

1. 使用初始化器语法来创建一个确定类型的空Set

2. 使用数组字面量创建Set,因为其遵循ExpressibleByArrayLiteral 协议

3. contains(:)集合是否包含某个元素


var letters = Set<Character>(["b","a","c"])
//无序性print(letters) //并不是按照初始化的顺序 :["c", "b", "a"]
//确定性print(letters.contains("a")) //trueprint(letters.contains("d")) //false

//互斥性//添加之前 ["c", "b", "a"]letters.insert("a")print(letters)  //之后:["c", "b", "a"],不存在相同的元素

var courses:Set = ["math","history","english"]print(courses) //Element的类型可以由编译器来推断,这里可以不写


Hashable

为了能让类型储存在Set当中,它必须是可哈希的——就是说类型必须提供计算它自身哈希值的方法(Hashable)。

所有Swift的基础类型(比如 String, Int, Double, 和 Bool)默认都是可哈希的,并且可以用于Set或者Dictionary的键。

Hashable继承Equalable,如果我们要在Set存储自定义类型,实现Hashable(func hash())的同时也需要实现Equalable(==)的要求,对于Struct,要求所有的存储属性是Hashable,对于Enum要求所有的关联类型是Hashable的.


struct Person{ var name :String var age :Int}
//Type 'Person' does not conform to protocol 'Hashable'var students = Set<Person>()
//自定义类型需要实现Hashable协议extension Person:Hashable{
func hash(into hasher: inout Hasher) { hasher.combine(self.name) }}extension Person:Equatable{ static func ==(lhs:Person,rhs:Person) -> Bool { return lhs.name == rhs.name }}
students.insert(Person(name: "小明", age: 20))students.insert(Person(name: "小明", age: 21)) //只判断name,所以这里插入不成功print(students) //[Set.Person(name: "小明", age: 20)]



03


Set的访问和修改


遍历

1.可以使用for_in 遍历Set

2.因为Set是无序的,如果要顺序遍历Set,可以使用sorted(),把集合的元素作为使用 < 运算符排序的数组返回。


let names:Set<String> = ["zhangsan","lisi","xiaohong","wangwu"]
for item in names{ print(item)}//zhangsan//wangwu//lisi//xiaohong
for name in names.sorted(){ print(name)}//lisi//wangwu//xiaohong//zhangsan


常用属性

1.使用count获取Set里元素个数

2.使用isEmpty判断Set是否为空

let names:Set<String> = ["zhangsan","lisi","xiaohong","wangwu"]print(names.count) //4print(names.isEmpty) //false


添加元素

1. insert(_:) 添加一个元素到Set

2. update(with:) 如果已经有相等的元素,替换为新元素。如果Set中没有,则添加这个元素


struct Animal { var legs:Int var name:String}extension Animal:Hashable{ func hash(into hasher: inout Hasher) { hasher.combine(self.name) }}
extension Animal:Equatable{ static func == (lhs:Animal,rhs:Animal) -> Bool{ return lhs.name == rhs.name }}
var animals:Set<Animal> = [Animal(legs: 2, name: "Man"),Animal(legs: 4, name: "外星人")]
animals.insert(Animal(legs: 4, name: "Dog"))
print(animals)//[Set.Animal(legs: 4, name: "Dog"), Set.Animal(legs: 2, name: "Man"), Set.Animal(legs: 4, name: "外星人")]

let (success,_) = animals.insert(Animal(legs: 2, name: "外星人"))print(success) //插入失败false
//使用updateanimals.update(with: Animal(legs: 2, name: "外星人"))print(animals) //更新成功//[Set.Animal(legs: 2, name: "Man"), Set.Animal(legs: 4, name: "Dog"), Set.Animal(legs: 2, name: "外星人")]


移除元素

1.remove(_:) 从Set当中移除一个元素,如果元素是Set的成员就移除它,并且返回移除的值,如果合集没有这个成员就返回nil 。

2.removeFirst() 移除Set的第一个元素,因为Set是无序的,所以第一个元素并不是放入的第一个元素。

3.removeAll() 移除所有元素


var chars:Set = ["a","b","c","d"]if let d = chars.remove("d"){ print(d) //d}else{ print("不存在")}
chars.removeFirst()print(chars) //["c", "a"]
chars.removeAll()print(chars.isEmpty) //true


filter过滤

filter(_:) 返回一个新的Set,新Set的元素是原始Set符合条件的元素。


let numbers:Set<Int> = [1,3,4,6,8,9,100]print(numbers.filter{ $0 % 2 == 0 } ) //[4, 100, 6, 8]


04


Set的合集


使用集合这个数据结构另一方面就在于可以高效地执行基本的合集操作,比如合并两个合集,确定两个合集共有哪个值,或者确定两个合集是否包含所有、某些或没有相同的值.


1. intersection(_:) 交集,属于A且属于B的相同元素组成的集合,记作A∩B(或B∩A)。

2. union(_:) 并集,所有属于集合A或属于集合B的元素所组成的集合,记作A∪B(或B∪A)。

3. symmetricDifference(_:) 对称差集,集合A与集合B的对称差集定义为集合A与集合B中所有不属于A∩B的元素的集合。即(A∪B)-(A∩B)

4. subtracting(_:) 相对补集,属于A而不属于B的元素组成的集合,称为B关于A的相对补集,记作A-B或A\B。即:A-(A∩B)


let set:Set<Character> = ["A","C","E"]let set2:Set<Character> = ["D","C","F","H"]
print(set.intersection(set2)) //["C"]print(set.union(set2)) //["F", "D", "C", "H", "A", "E"]
print(set.symmetricDifference(set2)) //["F", "D", "H", "A", "E"]print(set.subtracting(set2)) //["A", "E"]


对应的可变版本,调用的集合必须是var 可变的

1. formIntersection

2. formUnion

3. formSymmetricDifference

4. subtract

更多关于集合的操作可以查看SetAlgebra协议


合集成员关系和相等性


下面的示例描述了三个合集—— a, b和 c——用重叠区域代表合集之间值共享。合集 a是合集 b的超集,因为 a包含 b的所有元素。相反地,合集 b是合集 a的子集,因为 b的所有元素被 a包含。合集 b和合集 c是不相交的,因为他们的元素没有相同的。

1. == 判断两个集合是否包含相同的值

2. isSubset(of:) 判断是否是另一个Set或者Sequence的子集

3. isSuperset(of:) 判断是否是另一个Set或者Sequence的超集

4. isStrictSubset(of:) 和isStrictSuperset(of:) 判断是否是另一个Set的子集或者超集,但是又不等于另一个Set

5. isDisjoint(with:) 判断两个Set是否有公共元素(即是否不相交),如果没有返回true,如果有返回false


let smallSet:Set<Int> = [1,2,3]let bigSet:Set<Int> = [1,2,3,4]let otherSet:Set<Int> = [3,2,1]

print(smallSet == otherSet) // trueprint(smallSet.isSubset(of: bigSet)) //trueprint(bigSet.isSuperset(of: smallSet)) //trueprint(smallSet.isStrictSubset(of: otherSet)) //falseprint(smallSet.isStrictSuperset(of: otherSet)) //falseprint(smallSet.isDisjoint(with: bigSet)) //false


05


SetAlgebra


Set 和 OptionSet 是标准库中唯一实现了 SetAlgebra 的类型,Foundation之外的类型还有IndexSet 和 CharacterSet.


IndexSet 表示一个由正整数组成的集合,比直接使用Set<Int> 更加高效,因为它内部使用了一组范围列表进行实现。比如,现在你有一个含有 1000个元素的 table view,你想要一个集合来管理已经被用户选中的元素的索引。使用 Set<Int> 的话,根据选中的个数不同,最多可能会要存储 1000 个元素。而 IndexSet 不太一样,它会存储连续的范围,也就是说,在选取前 500 行的情况下,IndexSet 里其实只存储了选择的首位和末位两个整数值。

IndexSet 通过 rangeView 属性暴露了一个视图,也是一个集合类型.


var indices = IndexSet()
indices.insert(integersIn: 1..<5)indices.insert(integersIn: 10..<15)print(indices.rangeView)
indices.forEach { print($0,terminator: " ")}//1 2 3 4 10 11 12 13 14
indices.rangeView.forEach { print($0)}//1..<5//10..<15


CharacterSet,一个高效的存储 Unicode 编码点 (code point) 的集合。它经常被用来检查一个特定字符串是否只包含某个字符子集 (比如字母数字 alphanumerics 或者数字 decimalDigits) 中的字符。在开发中经常使用,

CharacterSet 并不是一个集合类型


CharacterSet.whitespaces //空格

CharacterSet.whitespacesAndNewlines //空格和换行

CharacterSet.lowercaseLetters //小写英文字母

CharacterSet.uppercaseLetters //大写英文字母

CharacterSet.letters //英文字母

CharacterSet.decimalDigits //数字 0-9

CharacterSet.alphanumerics //数字加字母

CharacterSet.letters.inverted //inverted相反的字符集 取反操作

print(CharacterSet.alphanumerics.contains("A")) //true
var nums = CharacterSet([UnicodeScalar("1"),UnicodeScalar("2")])print(CharacterSet.decimalDigits.isSuperset(of: nums)) //true

var string = " one two three "print(string.trimmingCharacters(in: CharacterSet.whitespaces)) //删除首尾空格


版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《Swift | Set集合》的版权归原作者「忧郁的思想家」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注忧郁的思想家微信公众号

忧郁的思想家微信公众号:YuYu19970314

忧郁的思想家

手机扫描上方二维码即可关注忧郁的思想家微信公众号

忧郁的思想家最新文章

精品公众号随机推荐