swift函数式编程日记

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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容