美文网首页iOS 底层面试
Swift高阶函数-map、compactMap、filter、

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

作者: loongod | 来源:发表于2022-06-30 15:00 被阅读0次

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

    相关文章

      网友评论

        本文标题:Swift高阶函数-map、compactMap、filter、

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