Swift高阶函数-map、compactMap、filter、
2022-06-30 本文已影响0人
loongod
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
个方法有些类似的,差别在于闭包的定义。
-
第一个函数闭包,接收
Result
和Element
,返回闭包执行后的Result
,后续的操作是将每次闭包执行后的Result
当做下一个元素执行闭包的入参,遍历完所有元素; -
第二个函数闭包,接收的也是
Result
和Element
,没有返回值,并且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
}
}