美文网首页
swift函数式编程日记

swift函数式编程日记

作者: 扶摇先生 | 来源:发表于2022-04-14 20:11 被阅读0次

    map,一一遍历处理,映射为一个新的数组
    filter,选出条件判断返回值为true的元素

    //MARK: 函数式编程
    var arr = [1,2,3,4]
    
    var arr1 = arr.map { i in
        i * 2
    }
    //等价于
    var arr2 = arr.map { $0*2 }
    //map,一一遍历处理,映射为一个新的数组
    print(arr1,arr2)
    //[2,4,6,8][2,4,6,8]
    
    //筛选,选出返回值为true的
    var arr3 = arr.filter { $0%2 == 0 }
    print(arr3)
    //[2,4]
    

    @inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
    第一个参数,传入一个初始化的结果,第二个参数为 两个参数的闭包(result,element),其中第一个参数有初始化值(第一次进入遍历的时候)为该方法的第一个参数initialResult,第二个参数为遍历数组元素,第二次遍历的时候Result的值为第一次遍历返回的值。第一次遍历结果为0x2+1 = 1,第二次遍历结果为1x2+2 = 4

    var arr4 = arr.reduce(0) {$0 * 2 + $1}
    //等价于
    arr4 = arr.reduce(0, { partialResult, i in
        print(partialResult,i)
        return partialResult * 2 + i
    })
    //    @inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
    //第一个参数,传入一个初始化的结果,第二个参数为  两个参数的闭包(result,element),其中闭包的第一个参数有初始化值(第一次进入遍历的时候)为该方法的第一个参数initialResult,第二个参数为遍历数组元素,第二次遍历的时候Result的值为第一次遍历返回的值。第一次遍历结果为0x2+1 = 1,第二次遍历结果为1x2+2 = 4
    
    print(arr4,"9999999")
    //0 1
    //1 2
    //4 3
    //11 4
    //26 9999999
    

    flatMap:见代码

    var arr5 = arr.map { Array.init(repeating: $0, count: $0) }
    var arr6 = arr.flatMap { Array.init(repeating:$0,count:$0) }
    print(arr5)
    print(arr6)
    //[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
    //[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
    

    lazy.map是用到哪个值的时候才会遍历计算哪个值

    //lazy.map是用到哪个值的时候才会遍历计算哪个值
    let result = arr.lazy.map {
        (i: Int) -> Int in
        print("mapping \(i)")
        return i * 2
    }
    print("begin-----")
    print("mapped", result[0])
    print("mapped", result[1])
    print("mapped", result[2])
    print("end----")
    //begin-----
    //mapping 1
    //mapped 2
    //mapping 2
    //mapped 4
    //mapping 3
    //mapped 6
    //end----
    

    Optional的map 和flatMap
    Optional(可选型)的map和flatMap返回值都为可选型,为nil时,返回值为nil,如果返回值又被包了一个可选型,那么map原样返回,为一个可选型的可选型,但flatMap不再进行包装(可以理解为它比较智能,已经是可选型了就不再包装了)

    var num: Int? = 10
    var num1 = num.map { $0*2 }
    var num2: Int? = nil
    var num3 = num2.map { $0*2 }
    print(num1,num2,num3)
    //Optional(20) nil nil
    var num4 = num2.flatMap { $0*2 }
    var num5 = num.flatMap { $0*2 }
    print(num4,num5)
    //nil Optional(20)
    
    var num6 = num.map { Optional.some($0*2) }
    var num7 = num.flatMap { Optional.some($0*2) }
    print(num6,num7)
    //Optional(Optional(20)) Optional(20)
    
    //可选型和整型相加
    var num8 = (num != nil) ? (num! + 10) : nil//如果num不为nil 强制解包+10 如果为nil设置为nil
    //等价
    var num9 = num.map { $0 + 10 }
    print(num8,num9)
    //Optional(20) Optional(20)
    
    
    //练习使用
    var fmt = DateFormatter()
    fmt.dateFormat = "yyyy-MM-dd"
    var str:String? = "2011-09-10"
    var date1 = str != nil ? fmt.date(from: str!) : nil
    //等价
    var date2 = str.flatMap { fmt.date(from:$0) }
    print(date1,date2)
    //Optional(2011-09-09 16:00:00 +0000) Optional(2011-09-09 16:00:00 +0000)
    
    var score: String? = "90"
    //old
    var score1 = score != nil ? "score is \(score)" : "no score"
    //new
    var score2 = score.map { "score is \($0)" } ?? "no score"
    print(score1, score2)
    //score is Optional("90")  score is 90
    
    
    
    struct Person {
        var name: String
        var age: Int
    }
    var items = [
        Person(name: "jack", age: 20),
        Person(name: "rose", age: 21),
        Person(name: "kate", age: 22) ]
    // old
    func getPerson1(_ name: String) -> Person? {
        let index = items.firstIndex { $0.name == name }
        return index != nil ? items[index!] : nil
    }
    // new
    func getPerson2(_ name: String) -> Person? {
        return items.firstIndex {$0.name == name }.map { items[$0] }
     /* items.firstIndex遍历到符合条件的第一个元素就停止,并返回下标*/
    /* map { items[$0] }把上一个函数的返回值传到map,相当于index.map{items[$0]}*/
    }
    
    struct Person {
        var name: String
        var age: Int
        init?(_ json: [String : Any]) {
        guard let name = json["name"] as? String,
        let age = json["age"] as? Int else {
        return nil
        }
        self.name = name
        self.age = age
        }
    }
    var json:Dictionary? = ["name":"jack","age":10]
    //old
    var p1 = json != nil ? Person.init(json!) : nil
    //new
    var p2 = json.flatMap { Person.init($0) }
    
    

    函数式编程(Funtional Programming)

    // 假设要实现以下功能:[(num + 3) * 5 - 1] % 10 / 2
    var num = 1
    

    传统写法

    func add(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
    func sub(_ v1: Int, _ v2: Int) -> Int { v1 - v2 }
    func multiple(_ v1: Int, _ v2: Int) -> Int { v1 * v2 }
    func divide(_ v1: Int, _ v2: Int) -> Int { v1 / v2 }
    func mod(_ v1: Int, _ v2: Int) -> Int { v1 % v2 }
    divide(mod(sub(multiple(add(num, 3), 5),1),10),2)
    

    函数式写法

    func add(_ v1:Int) -> (Int) -> Int {
        return {
            v2 in
            return v2 + v1
        }
    }
    //可简写为
    func add(_ v1:Int) -> (Int) -> Int { { $0 + v1 } }
    //手动柯里化(currying),把多个参数的函数,变成只有一个参数的函数,并返回另一个函数。
    //其中上边复杂写法v2为返回的函数的参数,即可简写为$0,缩写为一行,即为简写的。
    //let fn = add(3),那么fn就是一个+3的函数,然后调用fn(num),就是add(3)(num),等价为num + 3
    //同理
    func sub(_ v1: Int) -> (Int) -> Int { { $0 - v1 } }
    func multiple(_ v1: Int) -> (Int) -> Int { { $0 * v1 } }
    func divide(_ v1: Int) -> (Int) -> Int { { $0 / v1 } }
    func mod(_ v1: Int) -> (Int) -> Int { { $0 % v1} }
    
    //把连个函数合并成一个函数
    func hebing<A,B,C>(_ f1:@escaping(A) -> B,_ f2:@escaping(B) -> C) -> (A) -> C {
        return { a  in
           return f2(f1(a))
        }
    }
    
    //等价于:自定义运算符
    infix operator >>> : AdditionPrecedence //调用为 f1 >>> f2
    func  >>><A,B,C>(_ f1:@escaping (A) -> B,_ f2:@escaping (B) -> C) -> (A) -> C  {
        { f2(f1($0)) }
    }
    let fn1 = hebing(hebing(hebing(hebing(add(3), multiple(5)), sub(1)) , mod(10)), divide(2))
    let fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
    
    print(fn(num),fn1(num))
    //4 4
    

    拓展:自定义运算符

    prefix operator 前缀运算符 对象前跟这个运算符 比如 -2
    postfix operator 后缀运算符 比如num--
    infix operator 中缀运算符 : 优先级组 1+2
    precedencegroup 优先级组 {
    associativity: 结合性(left\right\none)
    higherThan: 比谁的优先级高
    lowerThan: 比谁的优先级低
    assignment: true代表在可选链操作中拥有跟赋值运算符一样的优先级
    }
    

    柯里化

    什么是柯里化?
    a、将一个接受多参数的函数变换为一系列只接受单个参数的函数。
    Array、Optional的map方法接收的参数就是一个柯里化函数

    func add(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
    add(10,20)
    //柯里化
    func add(_ v1:Int) -> (Int) -> Int { { $0 + v1 } }
    add(10)(20)
    
    //将一个多参函数变成一个柯里化后的函数
    
    func add1(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
    func add2(_ v1: Int, _ v2: Int, _ v3: Int) -> Int { v1 + v2 + v3 }
    
    func currying1<A,B,C> (_ f1:@escaping (A,B) -> C) -> (A) -> (B) -> C {
    //将一个有 A类型,B类型两个参数返回C类型参数的函数,变成 一个只有A参数返回 只有一个B参数返回C参数的函数
        return {
           a in
            return {
                b in
                return f1(a,b)
            }
        }
    }
    //等价于
    func currying2<A,B,C> (_ f1:@escaping (A,B) -> C) -> (A) -> (B) -> C {
        {a in {b in f1(a,b )} }
    }
    //等价于
    //prefix func ~<A,B,C> (_ f1:@escaping (A,B) -> C) -> (A) -> (B) -> C {
    //    {a in {b in f1(a,b )} }
    //}
    //同理
    func currying<A, B, C, D>(_ fn: @escaping (A, B, C) -> D) -> (A) -> (B) -> (C) -> D {
    { a in { b in { c in fn(a, b, c) } } }
    }
    //等价于
    prefix func ~<A, B, C, D>(_ fn: @escaping (A, B, C) -> D) -> (A) -> (B) -> (C) -> D {
    { a in { b in { c in fn(a, b, c) } } }}
    let curryingAdd1 = currying1(add1)
    print(curryingAdd1(2)(6))
    //8
    let curryingAdd2 = currying(add2)
    print(curryingAdd2(1)(2)(3))
    //6
    //var fn = (~add)(3) >>> (~multiple)(5) >>> (~sub)(1) >>> (~mod)(10) >>> (~divide)(2) //不用手动柯里化原来的函数就可以add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
    //fn(num)
    

    溢出运算符

    var min = UInt8.min//0
    print(min,min - 1)
    print(min,min &- 1)//0,255, (Int8.max),如果直接打印min - 1的话会直接闪退
    //这时候提供溢出运算符&- 相当于转一圈回去。
    

    运算符重载

    类、结构体、枚举可以为现有的运算符提供自定义的实现,这个操作叫做:运算符重载
    struct Point {
        var x:Int,y:Int
    }
    func + (p1:Point,p2:Point) -> Point {
        return Point.init(x: p1.x + p2.x, y: p1.y + p2.y)
    }
    let p1 = Point.init(x: 1, y: 2)
    let p2 = Point.init(x: 3, y: 4)
    let p3 = p1 + p2
    
    print(p3)
    //Point(x: 4, y: 6)
    

    相关文章

      网友评论

          本文标题:swift函数式编程日记

          本文链接:https://www.haomeiwen.com/subject/kqxxertx.html