Set 访问和修改

优质
小牛编辑
125浏览
2023-12-01

Swift 5.x Set 访问和修改

1.遍历 Set


  • 可以使用for-in遍历Set
  • 因为Set是无序的, 如果要顺序遍历Set, 使用sorted()方法
let courses: Set = ["Math", "English", "History"]
for course in courses {
    print(course)
}
print("--- 分割线 ---")
for course in courses.sorted() {
    print(course)
}

输出结果:

English
History
Math
--- 分割线 ---
English
History
Math

2. 访问Set


  • 使用count获取Set里元素个数
  • 使用isEmpty判断Set是否为空
let set: Set<Character> = ["A", "B", "C"]
print(set.count)
print(set.isEmpty)

输出结果:

3
false

3. 添加元素


  • insert(_:)添加一个元素到Set
  • update(with:)如果已经有相等的元素(哈希一样), 替换为新元素. 如果Set中没有, 则插入.
struct Person {
    var name: String = ""
    var age: Int = 0
}
extension Person: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
    }
}
extension Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

var personSet: Set<Person> = [
    Person(name: "zhangsan", age: 23),
    Person(name: "lisi", age: 20)
]
personSet.update(with: Person(name: "zhangsan", age: 24))
print(personSet)

这里的Person 只计算name的哈希值, 并且只根据name判断两个Person对象是否相等

输出结果:

[
__lldb_expr_148.Person(name: "zhangsan", age: 24), 
__lldb_expr_148.Person(name: "lisi", age: 20)
]

由于这里只计算name的哈希值, 所以执行udpate时, 将原有的数据进行了更新, 而没有新增

如果改成

hasher.combine(name)
hasher.combine(age)

则会新增一条记录

[
__lldb_expr_150.Person(name: "zhangsan", age: 23), 
__lldb_expr_150.Person(name: "zhangsan", age: 24), 
__lldb_expr_150.Person(name: "lisi", age: 20)
]

4. 移除元素


  • 4.1 filter(_:)返回一个新的Set, 新Set的元素是原始Set符合条件的元素.
struct Person {
    var name: String = ""
    var age: Int = 0
}
extension Person: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(age)
    }
}
extension Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

var personSet: Set<Person> = [
    Person(name: "zhangsan", age: 23),
    Person(name: "lisi", age: 20),
    Person(name: "wangwu", age: 27)
]
let filterdSet = personSet.filter({$0.age < 25})
print(filterdSet)

输出结果:

[
__lldb_expr_152.Person(name: "zhangsan", age: 23), 
__lldb_expr_152.Person(name: "lisi", age: 20)
]
  • 4.2 remove(_:)Set当中移除一个元素, 如果元素是Set的成员就移除它, 并且返回移除的值, 如果集合没有这个成员就返回nil
struct Person {
    var name: String = ""
    var age: Int = 0
}
extension Person: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(age)
    }
}
extension Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

var personSet: Set<Person> = [
    Person(name: "zhangsan", age: 23),
    Person(name: "lisi", age: 20),
    Person(name: "wangwu", age: 27)
]
let removedElement: Person? = personSet.remove(Person(name: "zhangsan", age: 22))
print(removedElement ?? "集合不存在该元素")

由于age在哈希值计算范围内, 所以打印结果为

集合不存在该元素

如果去掉hasher.combine(age)这一行代码, 打印结果:

Person(name: "zhangsan", age: 23)
  • 4.3 removeAll() 移除所有元素
personSet.removeAll()
print(personSet)

输出结果:

[]
  • 4.4 removeFirst() 移除Set的第一个元素, 因为Set是无序的, 所以第一个元素并不是放入的第一个元素, 而是哈希计算排序后的第一个元素.
struct Person {
    var name: String = ""
    var age: Int = 0
}
extension Person: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
    }
}
extension Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

var personSet: Set<Person> = [
    Person(name: "zhangsan", age: 23),
    Person(name: "lisi", age: 20),
    Person(name: "wangwu", age: 27)
]
personSet.removeFirst()
print(personSet)

输出结果:

[
__lldb_expr_175.Person(name: "lisi", age: 20), 
__lldb_expr_175.Person(name: "wangwu", age: 27)
]

5. 基于Set操作的


  • 5.1 intersection(_:) 交集, 由属于A且属于B的相同元素组成的集合, 记作AnBBnA
  • 5.2 union(_:) 并集, 由所有属于集合A或属于集合B的元素所组成的集合, 记作AuBBuA
  • 5.3 symmetricDifference(_:) 对称差集, 集合A与集合B中所有不属于AnB的元素的集合.
  • 5.4 subtracting(_:) 相对补集, 由属于A而不属于B的元素组成的集合, 成为B关于A的相对补集, 记作A-BA\B

e.g.

let set1: Set<Character> = ["A", "B", "C"]
let set2: Set<Character> = ["B", "E", "F", "G"]
print("交集 AnB: " + set1.intersection(set2))
print("并集 AuB: " + set1.union(set2))
print("对称差集: " + set1.symmetricDifference(set2))
print("相对补集 A-B: " + set1.subtracting(set2))

输出结果:

```bash
交集 AnB: B
并集 AuB: FGBCAE
对称差集: GCEAF
相对补集 A-B: AC

5. Set判断方法

  • isSubset(of:) 判断是否是另外一个Set或者Sequence的子集
  • isSuperset(of:) 判断是否是另外一个Set或者Sequence的超集
  • isStrictSubset(of:)isStrictSuperset(of:) 判断是否是另外一个Set的子集或者超集, 但是又不等于另外一个Set
  • isDisjoint(with:) 判断两个Set 是否有公共元素, 如果没有返回true, 如果有返回false
let smallSet: Set = [1, 2, 3]
let bigSet: Set = [1, 2, 3, 4]
print(smallSet.isSubset(of: bigSet))
print(bigSet.isSuperset(of: smallSet))
print(smallSet.isStrictSubset(of: bigSet))
print(bigSet.isStrictSuperset(of: smallSet))
print(smallSet.isDisjoint(with: bigSet))

输出结果:

true
true
true
true
false