CollectionExtension 1.1.0

CollectionExtension 1.1.0

Nayanda Haberty 维护。



  • 作者:
  • hainayanda

CollectionExtension

包含 Array、Sequence 和任何 Collection 扩展的集合

Codacy Badge build test SwiftPM Compatible Version License Platform

示例

要运行示例项目,首先克隆仓库,然后在 Example 目录中运行 pod install

要求

  • Swift 5.0 或更高版本(或当使用 Swift Package Manager 时为 5.3)
  • iOS 10.0 或更高版本

仅 Swift Package Manager

  • macOS 10.0 或更高版本
  • tvOS 10.10 或更高版本

安装

Cocoapods

CollectionExtension 通过 CocoaPods 提供。要安装它,只需将以下行添加到 Podfile 中

pod 'CollectionExtension'

XCode 中的 Swift Package Manager

  • 使用 XCode 菜单 文件 > Swift Package > 添加包依赖 添加它
  • https://github.com/hainayanda/CollectionExtension.git 作为 Swift Package URL 添加
  • 版本 中设置规则,使用 至下一个主要版本 选项,并设置 1.0.0 作为其版本
  • 点击下一步并等待

Package.swift 中的 Swift Package Manager

Package.swift 中将其添加为目标依赖项

dependencies: [
  .package(url: "https://github.com/hainayanda/CollectionExtension.git", .upToNextMajor(from: "1.0.0"))
]

在您的目标中使用 CollectionExtension

 .target(
    name: "MyModule",
    dependencies: ["CollectionExtension"]
)

作者

hainayanda,[email protected]

许可证

CollectionExtension 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。


基本用法

CollectionExtension 是一个包含 Array、Dictionary、Sequence 和 Collection 扩展的库,可用于更复杂的操作。以下是该库中包含的扩展功能列表。

安全索引(除了集合部分外的 Array 和任何 Collection,只在 Array 中可用)

类似于索引,但如果索引超出范围将返回 nil

// if the array count is less than 100, it will return a nil
let safeResult = myArray[safe: 100]

// if the array count is less than 100, it will do nothing
myArray[safe: 100] = someValue

// if 10 is in bounds, it will remove the value at index 10
myArray[safe: 10] = nil

// if 10 is the same as count, it will do append instead
myArray[safe: 10] = someValue

类型擦除(任何 Sequence 和 LazySequence)

使用函数式风格现在更容易对 Sequence 进行类型擦除

let typeErased: AnySequence<Some> = myArray.eraseToAnySequence()

let lazyTypeErased: AnyLazySequence<Some> = myArray.lazy.eraseToAnyLazySequence()

区分(任何 Sequence 和 LazySequence)

Sequence 过滤重复元素现在更容易,而不会牺牲性能同时保持其顺序

let myArray = [1, 1, 2, 3, 4, 4]

// will contain [1, 2, 3, 4]
let uniqueArray = myArray.unique

如果您的元素不是等价的,您可以使用具有 KeyPath、投影或闭包比较的 distinct 方法

// using projection
let uniqueArray = myArray.distinct { $0.identifier }

// using closure
let uniqueArray = myArray.distinct { $0.identifier == $1.identifier }

// using keypath
let uniqueArray = myArray.distinct(by: \.identifier)

// using object identifier if the element is a class instance
let uniqueArray = myArray.uniqueInstances

创建一个包含新元素的数组(Array)

使用添加而不是追加原始数组,将创建一个新数组,其中包含原始数组加上一个新元素

let myArray = [1, 2]

// [1, 2, 3]
let oneToThree = myArray.added(with: 3)

// [1, 2, 3, 4, 5]
let oneToFive = myArray.added(withContentsOf: [4, 5])

追加和插入不同的元素(Array)

在不牺牲性能的同时保持顺序的条件下,添加和插入不同元素会更容易

let myArray = [3, 4]

// will still contain [3, 4]
myArray.appendIfDistinct(4)

// will contain [3, 4, 5]
myArray.appendAllDistinct(in: [3, 4, 5])

// will contain [3, 4, 5]
myArray.insertIfDistinct(4, at: 0)

// will contain [1, 2, 3, 4, 5]
myArray.insertAllDistinct(in: [1, 2, 3, 4], at: 0)

如果您更喜欢创建一个新数组而不是追加原始数组,请使用 addedIfDistinct/addedAllDistinct 或 insertedIfDistinct/insertedAllDistinct。例如

let addedArray = myArray.addedIfDistinct(4)

如果您的元素不是等价的,您可以使用 KeyPath、投影或闭包比较。这也适用于 addedIfDistinct/addedAllDistinct 或 insertedIfDistinct/insertedAllDistinct

// using projection
myArray.appendIfDistinct(some) { $0.identifier }

// using closure
myArray.appendIfDistinct(some) { $0.identifier == $1.identifier }

// using keypath
myArray.appendIfDistinct(some, using: \.identifier)

// using object identifier if the element is a class instance
myArray.appendIfDistinctInstance(some)

减法、交集、对称差(任何 Sequence 和 LazySequence)

很容易对序列进行减法、交集和对称差异的操作

let left = [1, 2, 3, 4]
let right = [3, 4, 5, 6]

// [1, 2]
let substracted = left.substract(by: right)

// [3, 4]
let intersect = left.intersect(by: right)

// [1, 2, 5, 6]
let symetricDifference = left.symetricDifference(with: right)

与其他任何扩展一样,如果元素不是等价的,只需使用 KeyPath、投影或闭包比较即可。例如

// using projection
let substracted myArray.substract(by: some) { $0.identifier }

// using closure
let substracted myArray.substract(by: some) { $0.identifier == $1.identifier }

// using keypath
let substracted myArray.substract(by: some, by: \.identifier)

// using object identifier if the element is class instance
let substracted myArray.substractInstances(some)

移除元素(任何序列和延迟序列)

移除元素直到/之后找到元素,这非常简单。

let array = [1, 2, 3, 4, 5]

// [3, 4, 5]
let substracted = left.dropAllUntil { $0 == 3 }

// [1, 2, 3]
let substracted = left.dropAllAfter { $0 == 3 }

如果元素可比较,你可以这样做。

let array = [1, 2, 3, 4, 5]

// [3, 4, 5]
let substracted = left.dropAllUntil(find: 3)

// [1, 2, 3]
let substracted = left.dropAllAfter(find: 3)

统计(任何集合)

一些扩展可用于执行基本统计操作,例如求和、中位数、平均值等。

let array = [1, 2, 3, 4, 5]

// will produce .single(3)
let median: Median<Int> = array.median 

// will produce 15
let sum = array.sum 

// will produce 3
let sum = array.average 

// will produce 1
let smallest = array.smallest 

// will produce 5
let biggest = array.biggest 

我们还可以计算类似众数和频率的元素。

let array = [1, 1, 1, 2, 2, 3, 3, 3, 3]

// will produce 3
let modus = array.modus 

// will produce 2
let twoCount = array.elementCount(2) 

// will produce [1: 2, 2: 2, 3: 4]
let group = array.groupedByFrequency()

当然,如果元素不可比较,我们可以简单地使用键路径、投影或闭包比较。示例

// using projection
myArray.modus { $0.identifier }

// using closure
myArray.modus { $0.identifier == $1.identifier }

// using keypath
myArray.modus(by: \.identifier)

// using object identifier if the element is a class instance
myArray.modusInstances

分组元素(任何序列)

我们可以将元素分组到数组元素的字典中。

let array = [1, 2, 3, 4, 5]

// will produce ["even": [2, 4], "odd": [1, 3, 5]]
let group = array.group { $0 % 2 == 0 ? "even": "odd" }

或使用键路径

let group = array.group(by: \.someProperty)

转换为字典(任何序列)

您可以将任何序列转换为类似分组元素的字典,但值将是一个元素而不是一个元素数组。

// using closure
let group = try array.transformToDictionary { $0.identifier }

// using keypath
let group = try array.transformToDictionary(keyedBy: \.identifier)

唯一的缺点是,如果键重复,则会抛出CollectionExtensionError.duplicatedKey错误。

映射键和值(任何字典)

您可以使用mapKeys方法将任何字典转换为具有不同键但相同值的另一个字典。

let result = myDictionary.mapKeys { $0.identifier }

请注意,如果键重复,则会抛出CollectionExtensionError.duplicatedKey错误。

如果您想用下一个找到的值覆盖重复的键,请使用overwriteMapKeys代替。

let result = myDictionary.overwriteMapKeys { $0.identifier }

如果您想忽略无法产生值的键,请使用compactMapKeys

let result = myDictionary.compactMapKeys { $0.identifier }

请注意,如果键重复,则会抛出CollectionExtensionError.duplicatedKey错误。

如果您在使用compactMapKeys的同时想要覆盖重复的键,请使用overwriteCompactMapKeys代替。

let result = myDictionary.overwriteCompactMapKeys { $0.identifier }

如果您需要一个键和值来生成一个新键,请使用

  • mapKeyValues而不是mapKeys
  • overwriteMapKeysValues而不是overwriteMapKeys
  • compactMapKeysValues而不是compactMapKeys
  • overwriteCompactMapKeysValues而不是overwriteCompactMapKeys

异步迭代(任何序列)

有时您想使用forEach或map迭代,但操作是异步的,您需要保留序列顺序。这个库可以做到这一点。

// regular
array.asyncForEach { element in
    await element.someTask()
}

// keep iterating even if there's an error in some task
array.asyncForEachIgnoreError { element in
    try await element.someTaskWithError()
}

// regular, if needed you can use asyncCompactMap
array.asyncMap { element in
    await element.produceSomeValue()
}

// keep iterating even if there's an error in some task, if needed you can use asyncCompactMapSkipError
array.asyncMapSkipError { element in
    try await element.produceSomeValueWithError()
}

如果您想使用Combine Future而不是Async Await,请使用

  • futureForEach而不是asyncForEach
  • futureForEachIgnoreError而不是asyncForEachIgnoreError
  • futureMap而不是asyncMap
  • futureMapSkipError而不是asyncMapSkipError
  • futureCompactMap而不是asyncCompactMap
  • futureCompactMapSkipError而不是asyncCompactMapSkipError

额外

如果需要,可以使用实现SequenceCollectionDoublyLinkedList类。


贡献

你知道怎么做。只需克隆并提交pull request即可。