• 【第六章-函数】1.函数的灵活性


    【6.1 函数的灵活性】

    一、笔记一
    sorted: 带返回值,原来的数据源不会改变
    sort: 不带返回值,就是改变自己
    
    • 1
    • 2
    例如1: sorted不影响原来的值
       func test1() {
            let myArray = [3, 1, 2]
            let res = myArray.sorted(by: <)
            
            var myArray1 = [3, 1, 2]
            myArray1.sort(by: <)
            
            
            print("res:\(res) myArray:\(myArray) myArray1: \(myArray1)")
            // 打印结果: res:[1, 2, 3] myArray:[3, 1, 2] myArray1: [1, 2, 3]
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    例如2:数组的元素是【元组】的排序
        func test2() {
            var numberStrings = [(2, "two"), (1, "one"), (3, "three")]
            numberStrings.sort(by: <)
            print("numberStrings: \(numberStrings)")
            // numberStrings: [(1, "one"), (2, "two"), (3, "three")]
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    二、笔记二
    API: lexicographicallyPrecedes
    字典学上的排序, 是不是在前面
    是在两个序列(简单理解为数组)之间使用
    @inlinable public func lexicographicallyPrecedes(_ other: OtherSequence, by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Bool where OtherSequence : Sequence, Element == OtherSequence.Element
    
    • 1
    • 2
    • 3
    • 4
    例如1: 字典顺序排序
      func test3() {
            let animals = ["elephant", "zebra", "dog"]
            let res = animals.sorted { lhs, rhs in
                let l = lhs.reversed()
                let r = rhs.reversed()
    
                return l.lexicographicallyPrecedes(r) // 字典上的排序   l 是不是 在 r 的前面
            }
            print("res:\(res)") // ["zebra", "dog", "elephant"]
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    三、笔记三
    系统类:排序描述符 NSSortDescriptor的使用
    
    • 1
    例如1: 字典顺序排序
    final class Person: NSObject {
        @objc var firstName: String
        @objc var lastName: String
        @objc var yearOfBirth: Int
        init(first: String, last: String, yearOfBirth: Int) {
            self.firstName = first
            self.lastName = last
            self.yearOfBirth = yearOfBirth
        }
        override var description: String {
            return self.firstName  + " " + self.lastName + "(" + String(self.yearOfBirth) + ")" + "\n"
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
     let people = [
          Person(first: "Jo", last: "Smith", yearOfBirth: 1972),
          Person(first: "Joe", last: "Smith", yearOfBirth: 1970),
          Person(first: "Joe", last: "Smyth", yearOfBirth: 1971),
          Person(first: "Joanne", last: "smith", yearOfBirth: 1985),
          Person(first: "Joanne", last: "smith", yearOfBirth: 1979),
          Person(first: "Robert", last: "Jones", yearOfBirth: 1975),
      ]
      
      func test4() {
          
          // 需求: (不区分大小写)
          // 1.先按 姓 排序
          // 2.再按 名 排序
          // 3.再按 出生年份 排序
          
          // 翻译 Descriptor: 描述符
          let lastDescriptor = NSSortDescriptor(key: #keyPath(Person.lastName), ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
          let firstDescriptor = NSSortDescriptor(key: #keyPath(Person.firstName), ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
          let yearDescriptor = NSSortDescriptor(key: #keyPath(Person.yearOfBirth), ascending: true)
          
          let descriptors = [lastDescriptor, firstDescriptor, yearDescriptor]
          let res = (people as NSArray).sortedArray(using: descriptors)
          print("res: \(res.description)")
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    上面使用的是运行时接口,我们如果要使用静态函数呢?
    Swift中并没有这类接口,我们可以使用函数

    例如2: 怎么样使用函数来达到NSSortDescriptor的效果?
    • 这一部分理解起来会比较难,可能需要一个小时
    1. 我们循序渐进,先按一个属性排序

    localizedCaseInsensitiveCompare : 按照当地规则无感知排序
    简单理解为是字符串中使用
    public func localizedCaseInsensitiveCompare(_ aString: T) -> ComparisonResult where T : StringProtocol

        func test5() { // 按照当地规则无感知排序(升序)
          var strings = ["Hello", "hallo", "Hallo", "hello"]
          strings.sort{ $0.localizedCaseInsensitiveCompare($1) == .orderedAscending}
          print("strings: \(strings)")
          
          // 只用某一个属性排序,也是很简单
          let res = people.sorted(by: {$0.yearOfBirth < $1.yearOfBirth})
          print("res:\(res)")
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    2. 对2个属性(姓和名)排序,使用看起来比较聪明的方法
        
      func test6() {
          
          /* 问题点:
           1. 每次构建一个数组是效率很低的
           2. 比较操作是写死的
           3. 无法对yearOfBirth进行比较
           */
          let res = people.sorted(by: {p0, p1 in
              let left = [p0.lastName, p0.firstName]
              let right = [p1.lastName, p1.firstName]
              
              return left.lexicographicallyPrecedes(right) {
                  $0.localizedCaseInsensitiveCompare($1) == .orderedAscending
              }
          })
          print("res: \(res)")
      }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    3. 函数作为数据
       typealias SortDescriptor = (Value, Value) -> Bool
       func test7() {
           let sortByYear: SortDescriptor = { $0.yearOfBirth < $1.yearOfBirth }
           let sortByLastName: SortDescriptor = { $0.lastName.localizedCaseInsensitiveCompare($1.lastName) == .orderedAscending }
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.1 我们想想,还有没有更通用的方法呢?

       /// 定义一个排序描述符函数
       /// - Parameters:
       ///   - key: 逃逸闭包: (Value) -> Key
       ///   - areInIncreasingOrder: 逃逸闭包: (Key, Key) -> Bool
       /// - Returns: 返回一个闭包: (Value, Value) -> Bool
       func sortDescriptor (key: @escaping (Value) -> Key, _ areInIncreasingOrder: @escaping (Key, Key) -> Bool) -> SortDescriptor {
           return { areInIncreasingOrder(key($0), key($1)) }
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.2 // MARK: 思考
    // key($0),key($1): 是什么?
    /*
    1. key的最终形态是什么?
    key看起来是一个逃逸闭包,这个逃逸闭包的返回值是Key
    所以说, key的最终形态是: 传入的闭包的返回值

    那么,在当前案例的调用中: let sortByYearAlt: SortDescriptor = sortDescriptor(key: { $0.yearOfBirth }, <)
    因为我们将返回结果泛型类型确定了: SortDescriptor, 这个泛型参数Value其实就是Person
    key = { Person in
    return Person.yearOfBirth
    }
    所以, 此案例情况下, key最终其实Person.yearOfBirth
    2. areInIncreasingOrder: 是闭包 (Key, Key) -> Bool
    我们这里的返回结果类型是什么呢? 是SortDescriptor => typealias SortDescriptor = (Value, Value) -> Bool
    可以知道,我们需要返回 (Value, Value) -> Bool 这种类型
    我们先回到调用的地方: sortDescriptor(key: { $0.yearOfBirth }, <)
    这里可以写成: sortDescriptor(key: { $0.yearOfBirth }, { $0 < $1 })
    key($0),表示 调用 key: @escaping (Value) -> Key
    调用传入第一个参数$0,即外面使用的时候,比如排序的时候,第一个元素
    同理, key($1), 表示调用的时候传入第二个元素
    在这里表示传入第一个Person1, 第二个Person2
    #
    得到的结果是第一个 Person1.yearOfBirth
    得到的结果是第二个 Person2.yearOfBirth
    #
    最后,返回一个闭包表达式 { areInIncreasingOrder(Person1.yearOfBirth, Person2.yearOfBirth) }
    闭包类型应该是: (Key, Key) -> Bool
    加{} 表示执行: { return Person1.yearOfBirth < Person2.yearOfBirth }
    #
    3. 总结来说: 就是传入2个参数,第一个参数表示: 获得传入一个类的某个属性的函数
    第二个参数表示: 对第一个参数的结果进行比较的方法,是比较大小,还是按字母排序,还是其他运算逻辑,等等
    */

          调用:
    
    • 1
        func test8() {
            // 使用第一个 sortDescriptor
            let sortByYearAlt: SortDescriptor = sortDescriptor(key: { $0.yearOfBirth }, < )
            let res = people.sorted(by: sortByYearAlt)
            print("res:\(res)")
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.3 为所有的遵守Comparable类型定义一个重载版本的函数

        func sortDescriptor(key: @escaping (Value) -> Key) -> SortDescriptor where Key: Comparable {
           return { key($0) < key($1) }
       }
    
    • 1
    • 2
    • 3

    3.4 增加支持3种排序方法的函数

        /// - Parameters:
        ///   - key: 要比较的具体类型
        ///   - ascending: 是否升序,默认升序
        ///   - comparator: 比较器
        func sortDescriptor(key: @escaping (Value) -> Key,
                                        ascending: Bool = true,
                                        _ comparator: @escaping (Key) -> (Key) -> ComparisonResult)
                                        -> SortDescriptor {
                                            return { lhs, rhs in
                                                let order: ComparisonResult = ascending
                                                    ? .orderedAscending // 升序
                                                    : .orderedDescending // 降序
                                                
                                                /*
                                                // 1. 首先: comparator 的类型是 `(Key)` (参数部分) -> `(Key) -> ComparisonResult`(返回类型)
                                                // 2. 所以: comparator(key(lhs))的类型就是返回的类型`(Key) -> ComparisonResult`
                                                let res1: (Key) -> ComparisonResult = comparator(key(lhs))
                                                
                                                // 3. 所以: 上述的res1再调用一次,返回的结果就是`ComparisonResult`类型
                                                let res2: ComparisonResult = res1(key(rhs))
                                                */
                                                
                                                // 4. 简写形式就是如下
                                                return comparator(key(lhs))(key(rhs)) == order
                                            }
                                        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    上面的comparator应该是理解的难点,为了更方便的理解,我们可以再自定义一个比较器,因为上述的比较器返回的是
    ComparisonResult:
    @frozen public enum ComparisonResult : Int, @unchecked Sendable {
    case orderedAscending = -1
    case orderedSame = 0
    case orderedDescending = 1
    }

    自定义一种年龄比较器

    extension Int {
        func myComparator(_ otherValue: Int) -> String {
            if self > otherValue {
                return "大于"
            } else if self == otherValue {
                return "等于"
            } else {
                return "小于"
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    
     // 自定义一种年龄比较器
        func sortDescriptor(key: @escaping (Value) -> Key,
                                        ascending: Bool = true,
                                        _ comparator: @escaping (Key) -> (Key) -> String)
                                        -> SortDescriptor {
                                            return { lhs, rhs in
                                                let order: ComparisonResult = ascending
                                                    ? .orderedAscending // 升序
                                                    : .orderedDescending // 降序
                                                
                                                /*
                                                // 1. 首先: comparator 的类型是 `(Key)` (参数部分) -> `(Key) -> String`(返回类型)
                                                // 2. 所以: comparator(key(lhs))的类型就是返回的类型`(Key) -> String`
                                                let res1: (Key) -> String = comparator(key(lhs))
                                                
                                                // 3. 所以: 上述的res1再调用一次,返回的结果就是`String`类型
                                                let res2: String = res1(key(rhs))
                                                */
                                                
                                                // 4. 简写形式就是如下
                                                return comparator(key(lhs))(key(rhs)) == "大于"
                                            }
                                        }
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    下面是两种调用方法的实现和打印结果:

    func test9() {
            // 使用重载版本的 sortDescriptor
            let sortByYearAlt: SortDescriptor = sortDescriptor(key: { $0.yearOfBirth })
            
            // 使用传比较器的   ( $0.localizedCaseInsensitiveCompare($1))
            let sortByFirstName: SortDescriptor = sortDescriptor(key: {$0.firstName}, String.localizedCaseInsensitiveCompare)
            let res = people.sorted(by: sortByFirstName)
            print(res)
            /*
             打印结果 res:
             [Jo Smith(1972)
             , Joanne smith(1985)
             , Joanne smith(1979)
             , Joe Smith(1970)
             , Joe Smyth(1971)
             , Robert Jones(1975)
             ]
             */
            
            // 传自定义的比较器
            let sortMy: SortDescriptor = sortDescriptor(key: {$0.yearOfBirth}, Int.myComparator)
            let res1 = people.sorted(by: sortMy)
            print(res1)
            /*
             打印结果res1:
             [Joanne smith(1985)
             , Joanne smith(1979)
             , Robert Jones(1975)
             , Jo Smith(1972)
             , Joe Smyth(1971)
             , Joe Smith(1970)
             ]
             */
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    1. 将多种比较器结合起来,根据优先级排序(比如说,
      a.先按姓排名,
      b.如果姓一样,再按名排名,
      c.如果姓名都一样,再按年龄排名
        func combine(sortDescriptors: [SortDescriptor]) -> SortDescriptor {
            return { lhs, rhs in
                for areInIncreasingOrder in sortDescriptors {
                    if areInIncreasingOrder(lhs, rhs) { return true }
                    if areInIncreasingOrder(rhs, lhs) { return false }
                }
                return false
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    调用:

        
        func test10() {
            let sortByYearAlt: SortDescriptor = sortDescriptor(key: { $0.yearOfBirth })
            let sortByFirstName: SortDescriptor = sortDescriptor(key: {$0.firstName}, String.localizedCaseInsensitiveCompare)
            let sortByLastName: SortDescriptor = sortDescriptor(key: {$0.lastName}, String.localizedCaseInsensitiveCompare)
            let combined: SortDescriptor = combine(sortDescriptors: [sortByLastName, sortByFirstName, sortByYearAlt])
            let res = people.sorted(by: combined)
            print(res)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    返回二阶函数

    /// 返回一个二阶函数
        /// - Parameter compare: 传入一个比较器(二阶函数)
        /// - Returns: 返回一个比较器(也是二阶函数),返回的比较器可以接受可选值
        func lift(_ compare: @escaping (A) -> (A) -> ComparisonResult) -> (A?) -> (A?) -> ComparisonResult {
            return { lhs in // 解析后成为: 一阶函数
                { rhs in // 再一次解析普通函数
                    switch (lhs, rhs) {
                    case (nil, nil):
                        return .orderedSame
                    case (nil, _):
                        return .orderedAscending
                    case (_, nil):
                        return .orderedDescending
                    case let (l?, r?): //也可以写成 (let l?, let r?), 这里简写成 let (l?, r?)
                        return compare(l)(r)
                    default: fatalError()
                    }
                }
            }
        }
        
        func test11() {
            let files = ["one.", "file.h", "file.c", "test.h"]
            
            let lcic = lift(String.localizedCaseInsensitiveCompare)
            let result = files.sorted(by: sortDescriptor(key: { $0.components(separatedBy: ".").last }, lcic))
            print(result)
        }
    
    最后总结:xxx
    xxx
    
    • 1
  • 相关阅读:
    Python每日一练 03
    苹果被迫弃用 Lightning?欧盟宣布 2024 年 Type-C 将 “一统天下”
    超越边界:如何ChatGPT 3.5、GPT-4、DALL·E 3和Midjourney共同重塑创意产业
    用DIV+CSS技术设计的凤阳旅游网站(web前端网页制作课作业)HTML+CSS+JavaScript
    Python中利用SQLAlchemy模块操作MySQL数据库
    std c++ 编写的 8 窗口出票模拟程序
    java计算机毕业设计校园二手交易系统源码+系统+mysql数据库+lw文档+部署
    关于#mysql#的问题:前端连接mysql数据库,实现查询(语言-javascript)
    Kafka在企业级应用中的实践
    HarmonyOS 自定义抽奖转盘开发(ArkTS)
  • 原文地址:https://blog.csdn.net/JH_Cao/article/details/128047416