领略一下 Swift 数组的高阶函数

1,049 阅读2分钟

前言

这篇文章会列举下列方法的使用示例:

  • mapflatMap —— 对元素进行变换
  • filter —— 只包含特定的元素
  • allSatisfty —— 针对一个条件测试所有的元素
  • reduce —— 将元素聚合成一个值
  • sort(by), sorted(by:) —— 排序
  • lexicographicallyPrecedes(_:by) —— 多参数排序
  • elementsEqual(_:by:)starts(with:by:) —— 将元素与另一个数组比较
  • split(whereSeparator) —— 把所有元素分成多个数组
  • prefix(while:) —— 从头取元素直到条件不成立
  • drop(while:) —— 条件为真时丢弃元素,不为真则返回其余的元素(和 prefix 类似,不过返回相反的集合)
  • removeAll(where) —— 删除所有符合条件的元素

map 和 flatMap

对元素进行变换。

// map
let arr = [1, 2, 3]
let brr = arr.map { "No." + String($0) }
// brr = ["No.1", "No.2", "No.3"]

// flatMap 第一种重载
let arr = [[1, 2, 3], [4, 5, 6]]
let brr = arr.flatMap { $0 }
// brr = [1, 2, 3, 4, 5, 6]

// 等价于
let brr = Array(arr.map { $0}.joined())

// flatMap 第二种重载
let arr: [Int?] = [1, 2, nil, 3, 4, nil, 5]
let brr = arr.flatMap { $0 }
// brr = [1, 2, 3, 4, 5]

fliter

只包含特定的元素。

let arr = [1, 2, 3]
let brr = arr.filter { $0 == 1 }
// brr = [1]

allSatisfty

针对一个条件测试所有的元素,全部元素都满足条件则返回 true,否则返回 false

let arr = [1, 2, 3, 4]
print(arr.allSatisfy { $0 >= 3 } ) // false
print(arr.allSatisfy { $0 >= 1 } ) // true

reduce

将元素聚合成一个值。

let arr = [1, 2, 3, 4, 5]
print(arr.reduce(10, +)) // 25 等价于 10+1+2+3+4+5

let arr = ["a", "b", "cd"]
print(arr.reduce("", +)) // abcd 等价于 ""+"a"+"b"+"cd"

sort(by), sorted(by:)

排序。

// sort 修改原数组,没有返回值;sorted 不修改原数组,返回一个新数组
let sortArr = [3, 4, 5, 2, 1]
let sortBrr = sortArr.sorted { $0 < $1 } // [1, 2, 3, 4, 5]

根据两个参数进行排序:

// 需求,先按 firstName 排序,再按 lastName 排序

let sortModel_1 = CustomSortModel(firstName: "a", lastName: "a_x")
let sortModel_2 = CustomSortModel(firstName: "a", lastName: "b_x")
let sortModel_3 = CustomSortModel(firstName: "b", lastName: "a_x")
let sortModel_4 = CustomSortModel(firstName: "b", lastName: "b_x")
let sortModel_5 = CustomSortModel(firstName: "c", lastName: "a_x")
let sortModel_6 = CustomSortModel(firstName: "c", lastName: "b_x")
let sortModelArr = 
    [sortModel_5, sortModel_1, sortModel_4, sortModel_2, sortModel_6, sortModel_3]
let sortModelBrr = sortModelArr.sorted {
    if $0.firstName != $1.firstName {
        return $0.firstName < $1.firstName
    }
    else {
        return $0.lastName < $1.lastName
    }
}
// [sortModel_1, sortModel_2, sortModel_3, sortModel_4, sortModel_5, sortModel_6]

lexicographicallyPrecedes(_:by:)

多参数排序,上面的多参数排序例子可以使用这个方法进行简化:

let brr = sortModelArr.sorted {
    let left = [$0.firstName, $0.lastName]
    let right = [$1.firstName, $1.lastName]
    return left.lexicographicallyPrecedes(right) { $0 < $1 }
}
// [sortModel_1, sortModel_2, sortModel_3, sortModel_4, sortModel_5, sortModel_6]

demo2: 比较两个字符串版本的大小:

let storeVersion = "1.13.10"
let currentVersion = "1.120.10"
let storeVersionArr = storeVersion.components(separatedBy: ".").map{ Int($0) ?? 0 }
let currentVersionArr = currentVersion.components(separatedBy: ".").map{ Int($0) ?? 0 }
// true
print(storeVersionArr.lexicographicallyPrecedes(currentVersionArr))

partition(by:)

符合条件的元素移动到最后,它不会保留原数组的顺序:

var partitionArr = [4, 3, 2, 5, 1, 3, 6, 2, 7]
let pIndex = partitionArr.partition { $0 > 3 }

// pIndex = 5
// partitionArr : [2, 3, 2, 3, 1, 5, 6, 4, 7]
// 需要注意的是它并不会进行排序

// 通过 prefix 或者 suiffx 取出
let head = partitionArr.prefix(upTo: pIndex)
let end = partitionArr.suffix(from: pIndex)
// head: [2, 3, 2, 3, 1]
// suffix: [5, 6, 4, 7]

elementsEqual(_:by:) 和 starts(with:by:)

将元素与另一个数组比较。

// elementsEqual(_:by:)  比较序列中每一个元素是否相等
let arr = [1, 2, 3, 4]
let arr_1 = [1, 2, 3, 4]
let arr_2 = [2, 1, 3, 4]
let set: Set = [1, 2, 3, 4]
print(arr.elementsEqual(arr_1))	// true
print(arr.elementsEqual(arr_2)) // false
print(arr.elementsEqual(set))   // false

// starts(with:by:)
let arr = [1, 2, 3]
let brr = [1, 2, 3, 4, 5]
print(brr.starts(with: arr)) // true

split(whereSeparator:)

把所有元素分成多个数组。

let arr = ["A", "B", "C", "D", "B"]
// 遍历数组,当元素满足条件时,进行切割,生成切片
let arrSlices = try arr.split(whereSeparator: { $0 == "B" })
print(arrSlices) // [ArraySlice(["A"]), ArraySlice(["C", "D"])]

prefix(while:) 和 drop(while:)

let arr = ["A", "B", "C", "D"]
print(arr.prefix(2))          // ["A", "B"] 
print(arr.prefix(upTo: 2))    // ["A", "B"]
print(arr.prefix(through: 2)) // ["A", "B", "C"]
print(arr.dropFirst())        // ["B", "C", "D"]
print(arr.dropLast(2))        // ["A", "B"]
print(arr.suffix(2))          // ["C", "D"]

removeAll(where:)

删除所有符合条件的元素。

var arr = ["A", "B", "C", "D", "B"]
try arr.removeAll(where: { $0 == "B" })
print(arr) // ["A", "C", "D"]

结尾

Swift 封装这些函数的目的是为了让开发者摆脱代码中杂乱无趣的部分,让开发者能将重心放到真正想要表达的逻辑代码之中,所以在遇到数组相关的处理之前,先找一下有没有已经封装好的方法,是比较好的选择。

转载请注明 [出处](# 领略一下 Swift 数组的高阶函数)。