[docs] Extensions.md: Collections & Sequences section

This commit is contained in:
Daniel Arantes Loverde
2026-08-29 19:26:46 -03:00
parent 1d2c595c78
commit c459c9eaf6

View File

@@ -676,7 +676,445 @@ bytes.string // "hi"
## Collections & Sequences
<!-- batch 4 -->
<details>
<summary><b>Array</b> — dedup, mutation helpers (<code>Element: Equatable</code>)</summary>
### `var unique: [Element]` / `func withoutDuplicates() -> [Element]`
New array with duplicates dropped, first occurrence kept (order preserved).
```swift
[1, 2, 2, 3].unique // [1, 2, 3]
```
### `mutating func removeDuplicates() -> [Element]`
In-place dedup (`@discardableResult`).
### `func withoutDuplicates<E: Equatable>(keyPath:) -> [Element]` / `<E: Hashable>(keyPath:)`
Dedup by a key path. The `Hashable` overload is O(n).
```swift
users.withoutDuplicates(keyPath: \.id)
```
### `var removeNilElements: [Element]`
`compactMap { $0 }` — only meaningful when `Element` is itself optional.
### `mutating func removeAll(_ item: Element) -> [Element]` / `removeAll(_ items: [Element])`
Remove every occurrence of one value / of any value in a list (`@discardableResult`).
```swift
var a = [1, 2, 2, 3]; a.removeAll(2) // [1, 3]
var b = [1, 2, 3, 4]; b.removeAll([2, 4]) // [1, 3]
```
### `mutating func prepend(_ newElement: Element)`
Insert at index 0.
### `mutating func safeSwap(from:to:)`
Swap two indices; silently no-ops if either is out of bounds or equal.
```swift
var a = [1, 2, 3]; a.safeSwap(from: 0, to: 2) // [3, 2, 1]
a.safeSwap(from: 0, to: 9) // unchanged
```
</details>
<details>
<summary><b>Collection</b> — safe indexing, chunking, indices, averages</summary>
### `var fullRange: Range<Index>`
`startIndex..<endIndex`.
### `subscript(safe index:) -> Element?` / `subscript(exist index:) -> Element?`
Bounds-checked access, `nil` instead of a crash.
```swift
let a = [1, 2, 3]
a[safe: 1] // 2
a[safe: 9] // nil
```
### `func group(by size: Int) -> [[Element]]?`
Split into chunks of `size` (last chunk may be shorter). `nil` when empty or `size <= 0`.
```swift
[0, 2, 4, 7, 6].group(by: 2) // [[0, 2], [4, 7], [6]]
```
### `func forEach(slice: Int, body: ([Element]) -> Void)`
Iterate in chunks without building the intermediate array.
```swift
[0, 2, 4, 7].forEach(slice: 2) { print($0) } // [0, 2] then [4, 7]
```
### `func indices(where condition:) -> [Index]?`
All indices matching a predicate, `nil` if none.
```swift
[1, 7, 1, 2, 1].indices(where: { $0 == 1 }) // [0, 2, 4]
```
### `func indices(of item: Element) -> [Index]` — *(`Element: Equatable`)*
All indices equal to `item`.
### `func adjacentPairs() -> AnySequence<(Element, Element)>`
Every unordered pair `(i, j)` with `i` before `j`.
```swift
Array([1, 2, 3].adjacentPairs()) // [(1, 2), (1, 3), (2, 3)]
```
### `func forEachInParallel(_:)`
`DispatchQueue.concurrentPerform` over the elements. No ordering guarantee.
### `func average() -> Double` *(`Element: BinaryInteger`)* / `func average() -> Element` *(`Element: FloatingPoint`)*
Mean, `0` for an empty collection.
```swift
[1, 2, 3, 4].average() // 2.5
[1.2, 2.3, 4.5].average() // 2.666
```
</details>
<details>
<summary><b>BidirectionalCollection</b></summary>
### `subscript(offset distance: Int) -> Element`
Positive offset from the start, negative from the end.
```swift
let a = [1, 2, 3, 4, 5]
a[offset: 1] // 2
a[offset: -2] // 4
```
### `func last<T: Equatable>(where keyPath:, equals value:) -> Element?`
Last element whose key-path value equals `value`.
```swift
events.last(where: \.type, equals: .login)
```
</details>
<details>
<summary><b>Sequence</b> — predicates, key-path sorting, sums, dedup</summary>
### `func all(matching:)` / `func none(matching:)` / `func any(matching:)`
Whether the predicate holds for all / no / at least one element.
```swift
[2, 4, 6].all(matching: { $0 % 2 == 0 }) // true
[1, 3].any(matching: { $0 % 2 == 0 }) // false
```
### `func reject(where:) -> [Element]`
Inverse of `filter`.
```swift
[2, 3, 4, 7].reject(where: { $0 % 2 == 0 }) // [3, 7]
```
### `func count(where:) -> Int`
Number of elements matching a predicate.
### `func forEachReversed(_:)` / `func forEach(where:body:)`
Iterate right-to-left / iterate only matching elements.
### `func accumulate<U>(initial:next:) -> [U]`
Like `reduce` but returns every interim result.
```swift
[1, 2, 3].accumulate(initial: 0, next: +) // [1, 3, 6]
```
### `func filtered<T>(_ isIncluded:, map transform:) -> [T]`
`filter` + `map` in one lazy pass.
```swift
[1, 2, 3, 4].filtered({ $0 % 2 == 0 }, map: { "\($0)" }) // ["2", "4"]
```
### `func single(where:) -> Element?`
The one matching element, or `nil` if zero or more than one match.
```swift
[1, 4, 7].single(where: { $0 % 2 == 0 }) // 4
[2, 4].single(where: { $0 % 2 == 0 }) // nil
```
### `func divided(by condition:) -> (matching:, nonMatching:)`
Partition into two arrays.
```swift
let (even, odd) = [0, 1, 2, 3].divided { $0 % 2 == 0 } // ([0, 2], [1, 3])
```
### `func withoutDuplicates<T: Hashable>(transform:) -> [Element]`
Dedup by a derived hashable value.
```swift
[(1, "a"), (2, "b"), (1, "c")].withoutDuplicates { $0.0 } // [(1, "a"), (2, "b")]
```
### `func sorted(by keyPath:)` / `sorted(by keyPath:with:)` / `sorted(by:and:)` / `sorted(by:and:and:)`
Sort by one, two, or three key paths (later paths break ties). The `with:`
variant takes an explicit comparator.
```swift
people.sorted(by: \.lastName, and: \.firstName)
scores.sorted(by: \.value, with: >)
```
### `func sum() -> Element` *(`Element: AdditiveArithmetic`)* / `func sum<T: AdditiveArithmetic>(for keyPath:) -> T`
Total of the elements, or of a numeric property.
```swift
[1, 2, 3].sum() // 6
["ab", "cde"].sum(for: \.count) // 5
```
### `func first<T: Equatable>(where keyPath:, equals value:) -> Element?`
First element matching on a key path.
### `func contains(_ elements: [Element]) -> Bool` *(`Element: Equatable` or `Hashable`)*
Whether every element of `elements` is present (the `Hashable` overload is O(m+n)).
### `func containsDuplicates() -> Bool` / `func duplicates() -> [Element]` *(`Element: Hashable`)*
Whether any value repeats / the set of repeated values.
```swift
[1, 2, 2, 3, 3].duplicates().sorted() // [2, 3]
```
</details>
<details>
<summary><b>RangeReplaceableCollection</b> — rotate, take/skip, offset subscripts</summary>
### `init(expression:count:)`
Build a collection by evaluating an autoclosure `count` times.
```swift
Array(expression: Int.random(in: 0..<10), count: 3) // e.g. [4, 9, 1]
```
### `func rotated(by places: Int) -> Self` / `mutating func rotate(by:) -> Self`
Rotate elements; positive moves the tail to the front.
```swift
[1, 2, 3, 4].rotated(by: 1) // [4, 1, 2, 3]
[1, 2, 3, 4].rotated(by: -1) // [2, 3, 4, 1]
```
### `mutating func removeFirst(where:) -> Element?`
Remove and return the first match (`@discardableResult`).
### `mutating func removeRandomElement() -> Element?`
Remove and return a random element.
### `mutating func keep(while:) -> Self` / `func take(while:) -> Self` / `func skip(while:) -> Self`
`keep`/`take` return the leading run that matches; `skip` returns everything
after it.
```swift
[0, 2, 4, 7, 6].take(while: { $0 % 2 == 0 }) // [0, 2, 4]
[0, 2, 4, 7, 6].skip(while: { $0 % 2 == 0 }) // [7, 6]
```
### `mutating func removeDuplicates<E>(keyPath:)`
In-place dedup by an `Equatable` or `Hashable` key path.
### `subscript(offset: Int) -> Element` / `subscript<R: RangeExpression>(range:) -> SubSequence`
Get/set by integer offset or integer range.
```swift
var a = [10, 20, 30]; a[1] = 99 // [10, 99, 30]
a[0..<2] // [10, 99]
```
### `mutating func appendIfNonNil(_:)` / `appendIfNonNil(contentsOf:)`
Append only when the optional value / sequence is non-nil.
```swift
var a = [1]; a.appendIfNonNil(Optional<Int>.none) // [1]
a.appendIfNonNil(2) // [1, 2]
```
</details>
<details>
<summary><b>Dictionary</b> — key paths, JSON, key/value maps, merge operators</summary>
### `subscript(path path: [Key]) -> Any?`
Deep get/set through nested dictionaries.
```swift
var d: [String: Any] = ["a": ["b": ["c": 1]]]
d[path: ["a", "b", "c"]] // 1
d[path: ["a", "b", "c"]] = 2
```
### `var queryString: String`
`key=value&key=value` (no percent-encoding — encode yourself if needed).
```swift
["a": 1, "b": 2].queryString // "a=1&b=2" (order not guaranteed)
```
### `var convertToJSON: String`
Pretty-printed JSON, or an error description string on failure.
### `init(grouping sequence: by keyPath:)`
Group a sequence into `[Key: [Element]]` by a key path.
```swift
Dictionary(grouping: people, by: \.city)
```
### `func toObjetct<T: Codable & Sendable>() throws -> T`
Encode to JSON then decode into `T`. Throws `DecodingError` on a shape mismatch.
```swift
let user: User = try ["id": 1, "name": "Ana"].toObjetct()
```
### `func has(key:) -> Bool`
Key presence check.
### `mutating func removeAll<S: Sequence>(keys:)` / `static func - (lhs:keys:)` / `static func -= (lhs:keys:)`
Remove a set of keys — mutating, or as a new dictionary via `-` / `-=`.
```swift
var d = ["a": 1, "b": 2, "c": 3]
d -= ["a", "b"] // ["c": 3]
```
### `mutating func removeValueForRandomKey() -> Value?`
Remove and return one random entry's value.
### `func jsonData(prettify: Bool = false) -> Data?` / `func jsonString(prettify: Bool = false) -> String?`
Serialise to `Data` / `String`, `nil` if the dictionary isn't a valid JSON object.
### `func mapKeysAndValues<K, V>(_:) -> [K: V]` / `func compactMapKeysAndValues<K, V>(_:) -> [K: V]`
Transform both keys and values in one pass; the `compact` variant drops `nil` results.
```swift
["a": 1].mapKeysAndValues { ($0.key.uppercased(), $0.value * 10) } // ["A": 10]
```
### `func pick(keys: [Key]) -> [Key: Value]`
Sub-dictionary limited to the given keys.
### `static func + (lhs:rhs:)` / `static func += (lhs:rhs:)`
Merge two dictionaries (right wins on key clash).
### `func keys(forValue value:) -> [Key]` *(`Value: Equatable`)*
All keys mapping to a value.
### `mutating func lowercaseAllKeys()` *(`Key: StringProtocol`)*
Lowercase every key in place.
### `var uniqueValues: [Key: Value]` *(`Value: Hashable`)*
Keep only the first entry seen for each distinct value.
</details>
<details>
<summary><b>Optional</b> — safe unwrap, conditional assignment</summary>
### `func unwrapped(or defaultValue: Wrapped) -> Wrapped`
`self ?? defaultValue`, read nicely.
```swift
let name: String? = nil
name.unwrapped(or: "Guest") // "Guest"
```
### `func unwrapped(or error: Error) throws -> Wrapped`
Unwrap or throw a chosen error.
```swift
let id = try userId.unwrapped(or: AppError.missingID)
```
### `func run(_ block: (Wrapped) -> Void)`
Run a block only when non-nil (like `if let`, expression-style).
```swift
token.run { print("have token \($0)") }
```
### `static func ??= (lhs: inout Optional, rhs: Optional)`
Assign only if the right side is non-nil.
```swift
var params: String? = "a"; params ??= nil // still "a"
```
### `static func ?= (lhs: inout Optional, rhs: @autoclosure)`
Assign only if the left side is currently nil.
```swift
var text: String? = nil
text ?= "first" // "first"
text ?= "second" // still "first"
```
### `var isNilOrEmpty: Bool` / `var nonEmpty: Wrapped?` *(`Wrapped: Collection`)*
Nil-or-empty check; `nonEmpty` returns the collection only when it has content.
```swift
let list: [Int]? = []
list.isNilOrEmpty // true
list.nonEmpty // nil
```
### `static func == / != (Optional, Wrapped.RawValue?)` *(`Wrapped: RawRepresentable`)*
Compare an optional enum directly against an optional raw value.
```swift
let status: Status? = .active
status == "active" // true
```
</details>
<details>
<summary><b>Comparable</b></summary>
### `func isBetween(_ range: ClosedRange<Self>) -> Bool`
Range membership.
```swift
7.isBetween(6...12) // true
```
### `func clamped(to range: ClosedRange<Self>) -> Self`
Constrain a value to a range.
```swift
1.clamped(to: 3...8) // 3
0.32.clamped(to: 0.1...0.29) // 0.29
```
</details>
<details>
<summary><b>Bool</b></summary>
### `var int: Int` / `var string: String` / `var data: Data`
`1`/`0`, `"true"`/`"false"`, or a single-byte `Data`.
```swift
true.int // 1
false.string // "false"
```
</details>
## Numbers & Geometry