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
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章