文章

Swift高阶函数使用方式

1. map

1
2
3
4
{
	(Element) -> T in
	// Element的处理代码
}

简单说就是数组中每个元素通过某个方法进行操作,最后返回一个新的数组

白话点就是:遍历数组每个元素并都进行相同的操作,返回操作后获取到的值

1
2
3
4
let test = [1, 2, 3]
// 获取每个值的平方
let squares = test.map { $0 * $0 }
// [1, 4, 9]

2. flatMap

降维和过滤,swift4.1之后只有降纬,过滤nil给了compactMap,因为flatMap违背了单一功能原则

过滤nil,解析首层元素,若有nil则过滤,就不会降维

1
2
3
4
let optLatticeNumbers = [[1, Optional(2), 3], [3, nil, 5], nil]
// 解析首层元素, 若有nil则过滤, 就不会降维
let flatMapArr2 = optLatticeNumbers.flatMap { $0 }
// [[1, 2, 3], [3, nil, 5]]

降纬,二维数组变成一维数组,解析首层元素,若没有nil,则会降维

1
2
3
4
let latticeNumbers = [[1, Optional(2), 3], [3, nil, 5]]
// 解析首层元素, 若没有nil, 则会降维
let flatMapArr = latticeNumbers.flatMap { $0 }
// [1, 2, 3, 3, nil, 5]

3. compactMap

compactMap 方法同 map 方法比较类似,只不过它返回后的数组中不存在 nil(自动把 nil 给剔除掉),同时它会把 Optional 解包。

1
2
3
4
5
6
7
8
9
let test = ["rambo", "jhon", "", "test"]
let nonil = test2.compactMap { (str) -> String? in
    if str.count > 0 {
        return str
    } else {
        return nil
    }
}
// ["rambo", "jhon", "test"]

4. sort

原集合进行给定条件排序。无返回值,直接修改原集合,所以这个集合应该是可变类型的。

1
2
3
var sortArr = [1, 2, 3, 4, 5]
// 从小到大排序
sortArr.sort { $0 < $1 }  

5. sorted

sorted函数sort函数对应。将集合进行给定条件排序,返回一个新的集合,不修改原集合。

1
2
3
let numbers = [1, 2, 3, 4, 5]
// 从小到大排序
var sortArr = numbers.sorted { $0 < $1 }  

6. filter

filter 方法用于过滤元素,即筛选出数组元素中满足某种条件的元素。

1
2
3
4
{ 
	(Element) -> Bool in
	// Element的条件判断处理代码
}
1
2
3
4
let numbers = [1, 2, 3, 4, 5]
// 小于3的数
let arr = numbers.filter { $0 < 3 }  
// [1, 2]

7. reduce

reduce 方法把数组元素组合计算为一个值,并且会接受一个初始值,这个初始值的类型可以和数组元素类型不同。

1
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

initialResult 为初始值,Element 是要处理的元素,处理后返回Result 作为下次闭包的参数。

  • reduce 的基础思想是将一个序列转换为一个不同类型的数据,期间通过一个累加器(Accumulator)来持续记录递增状态。为了实现这个方法,我们会向 reduce 方法中传入一个用于处理序列中每个元素的结合(Combinator)闭包 / 函数 / 方法
  • reduce 是 map、flatMap 或 filter 的一种扩展的形式(后三个函数能干嘛,reduce 就能用另外一种方式实现)

具体例子,计算所有学生的年龄加载一起是多少。

1
2
3
4
let totalAges = stus.reduce(0) { (result, stu) in
    return result + stu.age
}
print(totalAges) // 62

该函数的第一个参数为初始值,后面元组中的第一个参数为每次计算的结果result,第二个参数为每次遍历的元素stu。最后将计算的结果返回。

1
2
3
let reduceString = ["C", "O", "D", "E"].reduce("word: ") { result, num in
    return result + num
}// "word: CODE"

8. prefix

正向取满足条件的元素,进行新集合创建。一旦出现不满足条件的元素,则跳出循环,不再执行。

1
2
3
4
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
// 找到第一个满足小于10的条件就跳出循环
let prefixArr = numbers.prefix { $0 < 10 } 
// [7, 6]

prefix相关函数:

  1. upTo: 正向取元素创建数组, 包含小于指定index的元素

    1
    2
    3
    
    // 取到下标为4的元素结束
    let prefixUpToArr = numbers.prefix(upTo: 5)
    // [7, 6, 10, 9, 8]
    
  2. through: 正向取元素创建数组, 包含小于等于指定index的元素

    1
    2
    3
    
    // 取到下标为2的元素结束
    let prefixThroughArr = numbers.prefix(through: 2)
    // [7, 6, 10]
    
  3. maxLength: 正向取元素创建数组, 包含指定的元素个数

    1
    2
    3
    
    // 取6个
    let prefixMaxLengthArr = numbers.prefix(6)
    // [7, 6, 10, 9, 8, 1]
    

9. drop函数

prefix函数对应。正向跳过满足条件的元素,进行新集合创建。一旦出现不满足条件的元素,则跳出循环,不再执行。

1
2
3
4
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
// 跳过符合条件<10的数据,取剩下的
let dropArr = numbers.drop { $0 < 10 }
// [10, 9, 8, 1, 2, 3, 4, 5]

drop相关函数:

  1. dropFirst: 正向跳过元素创建数组, 跳过指定元素个数, 缺省值为1
1
2
3
  // 丢弃前面三个
  let dropFirstArr = numbers.dropFirst(3)
  // [9, 8, 1, 2, 3, 4, 5]
  1. dropLast: 返向跳过元素创建数组, 跳过指定元素个数, 缺省值为1
1
2
3
  // 丢弃后面5个
  let dropLastArr = numbers.dropLast(5)
  // [7, 6, 10, 9, 8]

10. first函数

正向找出第一个满足条件的元素。

1
2
3
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let first = numbers.first { $0 < 7 }
// 6

11. last函数

first函数对应。反向找出第一个满足条件的元素。

1
2
3
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let last = numbers.last { $0 > 5 }
// 8

12. firstIndex函数

正向找出第一个满足条件的元素下标。

1
2
3
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let firstIndex = numbers.firstIndex { $0 < 7 }
// 1

13. lastIndex函数

反向找出第一个满足条件的元素下标。

1
2
3
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let lastIndex = numbers.lastIndex { $0 > 5 }
// 4

14. partition函数

按照条件进行重新排序,不满足条件的元素在集合前半部分,满足条件的元素后半部分,但不是完整的升序或者降序排列。 返回值为排序完成后集合中第一个满足条件的元素下标。

1
2
3
4
var partitionNumbers = [20, 50, 30, 10, 40, 20, 60]
let pIndex = partitionNumbers.partition { $0 > 30 }
// partitionNumbers = [20, 20, 30, 10, 40, 50, 60]
// pIndex = 4

15. min函数

按条件排序后取最小元素。

1
2
3
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let min = numbers.min { $0 % 5 < $1 % 5 }
// 10

min()函数,自然升序取最小。

1
2
let minDefault = numbers.min()
// 1

16. max函数

按条件排序后取最大元素。

1
2
3
let maxDictionary = ["aKey": 33, "bKey": 66, "cKey": 99]
let max = maxDictionary.max { $0.value < $1.value }
// (key "cKey", value 99)

max()函数,自然升序取最大。

1
2
let maxDefault = numbers.max()
// 10

17. removeAll函数

移除原集合中所有满足条件的元素。无返回值,直接修改原集合,所以这个集合应该是可变类型的。

1
2
3
4
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
var removeArr = numbers
removeArr.removeAll { $0 > 6 }
// [6, 1, 2, 3, 4, 5]

18. 集合遍历

forEach函数:

1
2
3
numbers.forEach { num in
    print(num)
}

for-in函数:

1
2
3
for num in numbers where num < 5 {
    print(num)
}

enumerated()函数配合使用:

1
2
3
for (index, num) in numbers.enumerated() {
    print("\(index)-\(num)")
}

关于集合遍历的性能问题,可以看这里enumerated() 和 enumerateObjectsUsingBlock

19. shuffled函数

shuffled函数,打乱集合中元素的的顺序。

1
2
3
let ascendingNumbers = 0...9
let shuffledArr = ascendingNumbers.shuffled()
// [3, 9, 2, 6, 4, 5, 0, 1, 7, 8]

20. contains函数

contains函数,判断集合中是否包含某元素。

1
2
3
4
let containsBool = numbers.contains(8)
let containsBool1 = numbers.contains(11)
// true
// false

21. split和joined函数

split函数,字符串的函数,按条件分割字符串,为子字符串创建集合。与Objective-C中的componentsSeparatedByString:方法类似。

1
2
3
4
5
6
7
let line = "123Hi!123I'm123a123coder.123"
let splitArr = line.split { $0.isNumber }
// ["Hi!", "I'm", "a", "coder."]

// 也可指定字符
let splitArr2 = line.split(separator: "1")
// ["23Hi!", "23I'm", "23a", "23coder.", "23"]

joined函数,数组元素连接指定字符拼接成一个字符串。与Objective-C中的componentsJoinedByString:方法类似。

1
2
3
4
5
6
let joined = splitArr.joined(separator: "_")
// "Hi!_I'm_a_coder."

// 也可以只传入字符
let joined2 = splitArr2.joined(separator: "#")
// "23Hi!#23I'm#23a#23coder.#23"

22. zip函数

将两个数组合并为一个元组组成的数组。

1
2
3
4
5
6
let titles = ["aaa", "bbb", "ccc"]
let numbers = [111, 222, 333]
let zipA = zip(titles, numbers)
for (title, num) in zipA {
    print("\(title)-\(num)")
}

打印结果:

1
2
3
aaa-111
bbb-222
ccc-333

文章参考

Swift - 高阶函数介绍(map、flatMap、filter、reduce)

Swift里的高阶函数

Swift集合类高阶函数

本文由作者按照 CC BY 4.0 进行授权