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

【6.1 函数的灵活性】

一、笔记一
sorted: 带返回值,原来的数据源不会改变
sort: 不带返回值,就是改变自己
例如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]
    }
例如2:数组的元素是【元组】的排序
    func test2() {
        var numberStrings = [(2, "two"), (1, "one"), (3, "three")]
        numberStrings.sort(by: <)
        print("numberStrings: \(numberStrings)")
        // numberStrings: [(1, "one"), (2, "two"), (3, "three")]
    }
二、笔记二
API: lexicographicallyPrecedes
字典学上的排序, 是不是在前面
是在两个序列(简单理解为数组)之间使用
@inlinable public func lexicographicallyPrecedes<OtherSequence>(_ other: OtherSequence, by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Bool where OtherSequence : Sequence, Element == OtherSequence.Element
例如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"]
        
    }
三、笔记三
系统类:排序描述符 NSSortDescriptor的使用
例如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"
    }
}

 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)")
  }

上面使用的是运行时接口,我们如果要使用静态函数呢?
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)")
  }
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)")
  }
  
3. 函数作为数据
   typealias SortDescriptor<Value> = (Value, Value) -> Bool
   func test7() {
       let sortByYear: SortDescriptor<Person> = { $0.yearOfBirth < $1.yearOfBirth }
       let sortByLastName: SortDescriptor<Person> = { $0.lastName.localizedCaseInsensitiveCompare($1.lastName) == .orderedAscending }
   }

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

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

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个参数,第一个参数表示: 获得传入一个类的某个属性的函数
第二个参数表示: 对第一个参数的结果进行比较的方法,是比较大小,还是按字母排序,还是其他运算逻辑,等等
*/

      调用:
    func test8() {
        // 使用第一个 sortDescriptor
        let sortByYearAlt: SortDescriptor<Person> = sortDescriptor(key: { $0.yearOfBirth }, < )
        let res = people.sorted(by: sortByYearAlt)
        print("res:\(res)")
    }

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

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

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

    /// - Parameters:
    ///   - key: 要比较的具体类型
    ///   - ascending: 是否升序,默认升序
    ///   - comparator: 比较器
    func sortDescriptor<Value, Key>(key: @escaping (Value) -> Key,
                                    ascending: Bool = true,
                                    _ comparator: @escaping (Key) -> (Key) -> ComparisonResult)
                                    -> SortDescriptor<Value> {
                                        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
                                        }
                                    }

上面的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 "小于"
        }
    }
}

 // 自定义一种年龄比较器
    func sortDescriptor<Value, Key>(key: @escaping (Value) -> Key,
                                    ascending: Bool = true,
                                    _ comparator: @escaping (Key) -> (Key) -> String)
                                    -> SortDescriptor<Value> {
                                        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)) == "大于"
                                        }
                                    }
    

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

func test9() {
        // 使用重载版本的 sortDescriptor
        let sortByYearAlt: SortDescriptor<Person> = sortDescriptor(key: { $0.yearOfBirth })
        
        // 使用传比较器的   ( $0.localizedCaseInsensitiveCompare($1))
        let sortByFirstName: SortDescriptor<Person> = 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<Person> = 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. 将多种比较器结合起来,根据优先级排序(比如说,
    a.先按姓排名,
    b.如果姓一样,再按名排名,
    c.如果姓名都一样,再按年龄排名
    func combine<Value>(sortDescriptors: [SortDescriptor<Value>]) -> SortDescriptor<Value> {
        return { lhs, rhs in
            for areInIncreasingOrder in sortDescriptors {
                if areInIncreasingOrder(lhs, rhs) { return true }
                if areInIncreasingOrder(rhs, lhs) { return false }
            }
            return false
        }
    }

调用:

    
    func test10() {
        let sortByYearAlt: SortDescriptor<Person> = sortDescriptor(key: { $0.yearOfBirth })
        let sortByFirstName: SortDescriptor<Person> = sortDescriptor(key: {$0.firstName}, String.localizedCaseInsensitiveCompare)
        let sortByLastName: SortDescriptor<Person> = sortDescriptor(key: {$0.lastName}, String.localizedCaseInsensitiveCompare)
        let combined: SortDescriptor<Person> = combine(sortDescriptors: [sortByLastName, sortByFirstName, sortByYearAlt])
        let res = people.sorted(by: combined)
        print(res)
    }

返回二阶函数

/// 返回一个二阶函数
    /// - Parameter compare: 传入一个比较器(二阶函数)
    /// - Returns: 返回一个比较器(也是二阶函数),返回的比较器可以接受可选值
    func lift<A>(_ 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值