Swift高阶函数-map、compactMap、filter、reduce

Swift中默认帮我们实现了很多方便的序列操作,一般称之为高阶函数,在编程中都有很实用的功能。推荐在日程编码中使用。减少代码量,提高可读性。

一、map

返回一个数组,其中包含给定闭包映射到序列元素的结果。

1.1 数组

let list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let mapList = list.map { $0 + 10 }
print(mapList)
---console
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Collection协议中源码

  @inlinable
  public func map<T>(
    _ transform: (Element) throws -> T
  ) rethrows -> [T] {
    // TODO: swift-3-indexing-model - review the following
    let n = self.count
    if n == 0 {
      return []
    }

    var result = ContiguousArray<T>()
    result.reserveCapacity(n)

    var i = self.startIndex

    for _ in 0..<n {
      result.append(try transform(self[i]))
      formIndex(after: &i)
    }

    _expectEnd(of: self, is: i)
    return Array(result)
  }

1.2 字典

map
let dic = ["k1": 1, "k2": 2, "k3": 3, "k4": 4, "k5": 5]
let mapDicList = dic.map { (key, value) in
    return key + "-\(value)"
}
print(mapDicList)
---console
["k2-2", "k3-3", "k1-1", "k5-5", "k4-4"]

Sequence协议中源码

  @inlinable
  public func map<T>(
    _ transform: (Element) throws -> T
  ) rethrows -> [T] {
    let initialCapacity = underestimatedCount
    var result = ContiguousArray<T>()
    result.reserveCapacity(initialCapacity)

    var iterator = self.makeIterator()

    // Add elements up to the initial capacity without checking for regrowth.
    for _ in 0..<initialCapacity {
      result.append(try transform(iterator.next()!))
    }
    // Add remaining elements, if any.
    while let element = iterator.next() {
      result.append(try transform(element))
    }
    return Array(result)
  }

1.3 mapValues--字典专属

返回一个新字典,其中包含由给定闭包转换的该字典的键值。

let mapValueDic = dic.mapValues { value in
    value + 10
}
print(mapValueDic)
---console
["k1": 11, "k4": 14, "k2": 12, "k3": 13, "k5": 15]

mapValues源码

extension _NativeDictionary { // High-level operations
  @inlinable
  internal func mapValues<T>(
    _ transform: (Value) throws -> T
  ) rethrows -> _NativeDictionary<Key, T> {
    let resultStorage = _DictionaryStorage<Key, T>.copy(original: _storage)
    _internalInvariant(resultStorage._seed == _storage._seed)
    let result = _NativeDictionary<Key, T>(resultStorage)
    // Because the current and new buffer have the same scale and seed, we can
    // initialize to the same locations in the new buffer, skipping hash value
    // recalculations.
    for bucket in hashTable {
      let key = self.uncheckedKey(at: bucket)
      let value = self.uncheckedValue(at: bucket)
      try result._insert(at: bucket, key: key, value: transform(value))
    }
    return result
  }
}

---

extension __CocoaDictionary {
  @inlinable
  internal func mapValues<Key: Hashable, Value, T>(
    _ transform: (Value) throws -> T
  ) rethrows -> _NativeDictionary<Key, T> {
    var result = _NativeDictionary<Key, T>(capacity: self.count)
    for (cocoaKey, cocoaValue) in self {
      let key = _forceBridgeFromObjectiveC(cocoaKey, Key.self)
      let value = _forceBridgeFromObjectiveC(cocoaValue, Value.self)
      try result.insertNew(key: key, value: transform(value))
    }
    return result
  }
}

二、compactMap

返回一个数组,其中包含使用此序列的每个元素调用给定转换闭包的非nil结果。

2.1 数组、字典

let tempList = ["1", "2", "3", "haha", "4"]
let compactMapList: [Int] = tempList.compactMap { el in
    print(el)
    return Int(el)
}
print(compactMapList)
---console
[1, 2, 3, 4]
let tempDic = ["k1": "1", "k2": "2", "k3": "haha", "k4": "4"]
let compactMapDic = tempDic.compactMap { (key, value) in
    return Int(value)
}
print(compactMapDic)
---console
[1, 4, 2]

Sequence源码

  @inlinable // protocol-only
  public func compactMap<ElementOfResult>(
    _ transform: (Element) throws -> ElementOfResult?
  ) rethrows -> [ElementOfResult] {
    return try _compactMap(transform)
  }

  // The implementation of compactMap accepting a closure with an optional result.
  // Factored out into a separate function in order to be used in multiple
  // overloads.
  @inlinable // protocol-only
  @inline(__always)
  public func _compactMap<ElementOfResult>(
    _ transform: (Element) throws -> ElementOfResult?
  ) rethrows -> [ElementOfResult] {
    var result: [ElementOfResult] = []
    for element in self {
      if let newElement = try transform(element) {
        result.append(newElement)
      }
    }
    return result
  }
}

2.2 compactMapValues--字典专属

let data = ["a": "1", "b": "three", "c": "///4///"]
let c: [String: Int] = data.compactMapValues { str in Int(str) }
---console
["a": 1]

Dictionary协议中源码

  @inlinable
  public func compactMapValues<T>(
    _ transform: (Value) throws -> T?
  ) rethrows -> Dictionary<Key, T> {
    let result: _NativeDictionary<Key, T> =
      try self.reduce(into: _NativeDictionary<Key, T>()) { (result, element) in
      if let value = try transform(element.value) {
        result.insertNew(key: element.key, value: value)
      }
    }
    return Dictionary<Key, T>(_native: result)
  }

三、filter

3.1 数组

let list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let retList = list.filter { $0 % 2 == 0 }
print(retList)
---console
[2, 4, 6, 8, 10]

Sequence源码

  @inlinable
  public __consuming func filter(
    _ isIncluded: (Element) throws -> Bool
  ) rethrows -> [Element] {
    return try _filter(isIncluded)
  }

  @_transparent
  public func _filter(
    _ isIncluded: (Element) throws -> Bool
  ) rethrows -> [Element] {

    var result = ContiguousArray<Element>()

    var iterator = self.makeIterator()

    while let element = iterator.next() {
      if try isIncluded(element) {
        result.append(element)
      }
    }

    return Array(result)
  }

3.2 字典

let dic = ["k1": 1, "k2": 2, "k3": 3, "k4": 4, "k5": 5]
let retList = dic.filter { $0.value > 3 }
print(retList)
---console
["k4": 4, "k5": 5]

Dictionary协议中源码

  @inlinable
  @available(swift, introduced: 4.0)
  public __consuming func filter(
    _ isIncluded: (Element) throws -> Bool
  ) rethrows -> [Key: Value] {
    // FIXME(performance): Try building a bitset of elements to keep, so that we
    // eliminate rehashings during insertion.
    var result = _NativeDictionary<Key, Value>()
    for element in self {
      if try isIncluded(element) {
        result.insertNew(key: element.key, value: element.value)
      }
    }
    return Dictionary(_native: result)
  }
}

四、reduce

主要是用来对集合中每个元素和叠加器做对应操作

// 函数一
@inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
// 函数二
@inlinable public func reduce<Result>(into initialResult: __owned Result, _ updateAccumulatingResult: (inout Result, Element) throws -> ()) rethrows -> Result

2个方法有些类似的,差别在于闭包的定义。

  • 第一个函数闭包,接收ResultElement,返回闭包执行后的Result,后续的操作是将每次闭包执行后的Result当做下一个元素执行闭包的入参,遍历完所有元素;

  • 第二个函数闭包,接收的也是ResultElement,没有返回值,并且Result是用inout修饰的,所以传入闭包的是Result的地址,所以闭包的执行都是基于Result进行操作的。

数组:

// 函数一用法:
let list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let ret = list.reduce(0) { partialResult, el in
    return partialResult + el
}
print(ret)
---console
55

// 函数二用法:
let ret2 = list.reduce(into: 0) { partialResult, el in
    partialResult += el
}
print(ret2)
---console
55

字典:

let dic = ["k1": 1, "k2": 2, "k3": 3, "k4": 4, "k5": 5]
let ret3 = dic.reduce(0) { partialResult, el in
    return partialResult + el.value
}
print(ret3)
---console
15

Sequence协议中源码:

函数一

  @inlinable
  public func reduce<Result>(
    _ initialResult: Result,
    _ nextPartialResult:
      (_ partialResult: Result, Element) throws -> Result
  ) rethrows -> Result {
    var accumulator = initialResult
    for element in self {
      accumulator = try nextPartialResult(accumulator, element)
    }
    return accumulator
  }

函数二

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

推荐阅读更多精彩内容