mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
829 lines
28 KiB
Swift
829 lines
28 KiB
Swift
//===--- SequenceAlgorithms.swift.gyb -------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
%{
|
|
|
|
# We know we will eventually get a Sequence.Element type. Define
|
|
# a shorthand that we can use today.
|
|
GElement = "Iterator.Element"
|
|
|
|
orderingExplanation = """\
|
|
/// The predicate must be a *strict weak ordering* over the elements. That
|
|
/// is, for any elements `a`, `b`, and `c`, the following conditions must
|
|
/// hold:
|
|
///
|
|
/// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
|
|
/// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
|
|
/// both `true`, then `areInIncreasingOrder(a, c)` is also
|
|
/// `true`. (Transitive comparability)
|
|
/// - Two elements are *incomparable* if neither is ordered before the other
|
|
/// according to the predicate. If `a` and `b` are incomparable, and `b`
|
|
/// and `c` are incomparable, then `a` and `c` are also incomparable.
|
|
/// (Transitive incomparability)
|
|
///"""
|
|
|
|
equivalenceExplanation = """\
|
|
/// The predicate must be a *equivalence relation* over the elements. That
|
|
/// is, for any elements `a`, `b`, and `c`, the following conditions must
|
|
/// hold:
|
|
///
|
|
/// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
|
|
/// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
|
|
/// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
|
|
/// `areEquivalent(a, c)` is also `true`. (Transitivity)
|
|
///"""
|
|
|
|
}%
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// enumerated()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension Sequence {
|
|
/// Returns a sequence of pairs (*n*, *x*), where *n* represents a
|
|
/// consecutive integer starting at zero, and *x* represents an element of
|
|
/// the sequence.
|
|
///
|
|
/// This example enumerates the characters of the string "Swift" and prints
|
|
/// each character along with its place in the string.
|
|
///
|
|
/// for (n, c) in "Swift".characters.enumerated() {
|
|
/// print("\(n): '\(c)'")
|
|
/// }
|
|
/// // Prints "0: 'S'"
|
|
/// // Prints "1: 'w'"
|
|
/// // Prints "2: 'i'"
|
|
/// // Prints "3: 'f'"
|
|
/// // Prints "4: 't'"
|
|
///
|
|
/// When enumerating a collection, the integer part of each pair is a counter
|
|
/// for the enumeration, not necessarily the index of the paired value.
|
|
/// These counters can only be used as indices in instances of zero-based,
|
|
/// integer-indexed collections, such as `Array` and `ContiguousArray`. For
|
|
/// other collections the counters may be out of range or of the wrong type
|
|
/// to use as an index. To iterate over the elements of a collection with its
|
|
/// indices, use the `zip(_:_:)` function.
|
|
///
|
|
/// This example iterates over the indices and elements of a set, building a
|
|
/// list of indices of names with five or fewer letters.
|
|
///
|
|
/// let names: Set = ["Sofia", "Camilla", "Martina", "Mateo", "Nicolás"]
|
|
/// var shorterIndices: [SetIndex<String>] = []
|
|
/// for (i, name) in zip(names.indices, names) {
|
|
/// if name.characters.count <= 5 {
|
|
/// shorterIndices.append(i)
|
|
/// }
|
|
/// }
|
|
///
|
|
/// Now that the `shorterIndices` array holds the indices of the shorter
|
|
/// names in the `names` set, you can use those indices to access elements in
|
|
/// the set.
|
|
///
|
|
/// for i in shorterIndices {
|
|
/// print(names[i])
|
|
/// }
|
|
/// // Prints "Sofia"
|
|
/// // Prints "Mateo"
|
|
///
|
|
/// - Returns: A sequence of pairs enumerating the sequence.
|
|
public func enumerated() -> EnumeratedSequence<Self> {
|
|
return EnumeratedSequence(_base: self)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// min(), max()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # a Comparable requirement.
|
|
% for preds in [True, False]:
|
|
% rethrows_ = "rethrows " if preds else ""
|
|
|
|
extension Sequence ${"" if preds else "where Iterator.Element : Comparable"} {
|
|
|
|
% if preds:
|
|
/// Returns the minimum element in the sequence, using the given predicate as
|
|
/// the comparison between elements.
|
|
///
|
|
${orderingExplanation}
|
|
/// This example shows how to use the `min(by:)` method on a
|
|
/// dictionary to find the key-value pair with the lowest value.
|
|
///
|
|
/// let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
|
|
/// let leastHue = hues.min { a, b in a.value < b.value }
|
|
/// print(leastHue)
|
|
/// // Prints "Optional(("Coral", 16))"
|
|
///
|
|
/// - Parameter areInIncreasingOrder: A predicate that returns `true`
|
|
/// if its first argument should be ordered before its second
|
|
/// argument; otherwise, `false`.
|
|
/// - Returns: The sequence's minimum element, according to
|
|
/// `areInIncreasingOrder`. If the sequence has no elements, returns
|
|
/// `nil`.
|
|
///
|
|
/// - SeeAlso: `min()`
|
|
% else:
|
|
/// Returns the minimum element in the sequence.
|
|
///
|
|
/// This example finds the smallest value in an array of height measurements.
|
|
///
|
|
/// let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
|
|
/// let lowestHeight = heights.min()
|
|
/// print(lowestHeight)
|
|
/// // Prints "Optional(58.5)"
|
|
///
|
|
/// - Returns: The sequence's minimum element. If the sequence has no
|
|
/// elements, returns `nil`.
|
|
///
|
|
/// - SeeAlso: `min(by:)`
|
|
% end
|
|
@warn_unqualified_access
|
|
public func min(
|
|
% if preds:
|
|
by areInIncreasingOrder: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> ${GElement}? {
|
|
var it = makeIterator()
|
|
guard var result = it.next() else { return nil }
|
|
for e in IteratorSequence(it) {
|
|
% if preds:
|
|
if try areInIncreasingOrder(e, result) { result = e }
|
|
% else:
|
|
if e < result { result = e }
|
|
% end
|
|
}
|
|
return result
|
|
}
|
|
|
|
% if preds:
|
|
/// Returns the maximum element in the sequence, using the given predicate
|
|
/// as the comparison between elements.
|
|
///
|
|
${orderingExplanation}
|
|
/// This example shows how to use the `max(by:)` method on a
|
|
/// dictionary to find the key-value pair with the highest value.
|
|
///
|
|
/// let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
|
|
/// let greatestHue = hues.max { a, b in a.value < b.value }
|
|
/// print(greatestHue)
|
|
/// // Prints "Optional(("Heliotrope", 296))"
|
|
///
|
|
/// - Parameter areInIncreasingOrder: A predicate that returns `true` if its
|
|
/// first argument should be ordered before its second argument;
|
|
/// otherwise, `false`.
|
|
/// - Returns: The sequence's maximum element if the sequence is not empty;
|
|
/// otherwise, `nil`.
|
|
///
|
|
/// - SeeAlso: `max()`
|
|
% else:
|
|
/// Returns the maximum element in the sequence.
|
|
///
|
|
/// This example finds the smallest value in an array of height measurements.
|
|
///
|
|
/// let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
|
|
/// let greatestHeight = heights.max()
|
|
/// print(greatestHeight)
|
|
/// // Prints "Optional(67.5)"
|
|
///
|
|
/// - Returns: The sequence's maximum element. If the sequence has no
|
|
/// elements, returns `nil`.
|
|
///
|
|
/// - SeeAlso: `max(by:)`
|
|
% end
|
|
@warn_unqualified_access
|
|
public func max(
|
|
% if preds:
|
|
by areInIncreasingOrder: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> ${GElement}? {
|
|
var it = makeIterator()
|
|
guard var result = it.next() else { return nil }
|
|
for e in IteratorSequence(it) {
|
|
% if preds:
|
|
if try areInIncreasingOrder(result, e) { result = e }
|
|
% else:
|
|
if e > result { result = e }
|
|
% end
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// starts(with:)
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # an Equatable requirement.
|
|
% for preds in [True, False]:
|
|
% rethrows_ = "rethrows " if preds else ""
|
|
|
|
extension Sequence ${"" if preds else "where Iterator.Element : Equatable"} {
|
|
|
|
% if preds:
|
|
/// Returns a Boolean value indicating whether the initial elements of the
|
|
/// sequence are equivalent to the elements in another sequence, using
|
|
/// the given predicate as the equivalence test.
|
|
///
|
|
${equivalenceExplanation}
|
|
/// - Parameters:
|
|
/// - possiblePrefix: A sequence to compare to this sequence.
|
|
/// - areEquivalent: A predicate that returns `true` if its two arguments
|
|
/// are equivalent; otherwise, `false`.
|
|
/// - Returns: `true` if the initial elements of the sequence are equivalent
|
|
/// to the elements of `possiblePrefix`; otherwise, `false`. If
|
|
/// `possiblePrefix` has no elements, the return value is `true`.
|
|
///
|
|
/// - SeeAlso: `starts(with:)`
|
|
% else:
|
|
/// Returns a Boolean value indicating whether the initial elements of the
|
|
/// sequence are the same as the elements in another sequence.
|
|
///
|
|
/// This example tests whether one countable range begins with the elements
|
|
/// of another countable range.
|
|
///
|
|
/// let a = 1...3
|
|
/// let b = 1...10
|
|
///
|
|
/// print(b.starts(with: a))
|
|
/// // Prints "true"
|
|
///
|
|
/// Passing a sequence with no elements or an empty collection as
|
|
/// `possiblePrefix` always results in `true`.
|
|
///
|
|
/// print(b.starts(with: []))
|
|
/// // Prints "true"
|
|
///
|
|
/// - Parameter possiblePrefix: A sequence to compare to this sequence.
|
|
/// - Returns: `true` if the initial elements of the sequence are the same as
|
|
/// the elements of `possiblePrefix`; otherwise, `false`. If
|
|
/// `possiblePrefix` has no elements, the return value is `true`.
|
|
///
|
|
/// - SeeAlso: `starts(with:by:)`
|
|
% end
|
|
public func starts<PossiblePrefix>(
|
|
with possiblePrefix: PossiblePrefix${"," if preds else ""}
|
|
% if preds:
|
|
by areEquivalent: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> Bool
|
|
where
|
|
PossiblePrefix : Sequence,
|
|
PossiblePrefix.${GElement} == ${GElement} {
|
|
|
|
var possiblePrefixIterator = possiblePrefix.makeIterator()
|
|
for e0 in self {
|
|
if let e1 = possiblePrefixIterator.next() {
|
|
if ${"try !areEquivalent(e0, e1)" if preds else "e0 != e1"} {
|
|
return false
|
|
}
|
|
}
|
|
else {
|
|
return true
|
|
}
|
|
}
|
|
return possiblePrefixIterator.next() == nil
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// elementsEqual()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # an Equatable requirement.
|
|
% for preds in [True, False]:
|
|
% rethrows_ = "rethrows " if preds else ""
|
|
|
|
extension Sequence ${"" if preds else "where Iterator.Element : Equatable"} {
|
|
|
|
% if preds:
|
|
/// Returns a Boolean value indicating whether this sequence and another
|
|
/// sequence contain equivalent elements, using the given predicate as the
|
|
/// equivalence test.
|
|
///
|
|
/// At least one of the sequences must be finite.
|
|
///
|
|
${equivalenceExplanation}
|
|
/// - Parameters:
|
|
/// - other: A sequence to compare to this sequence.
|
|
/// - areEquivalent: A predicate that returns `true` if its two arguments
|
|
/// are equivalent; otherwise, `false`.
|
|
/// - Returns: `true` if this sequence and `other` contain equivalent items,
|
|
/// using `areEquivalent` as the equivalence test; otherwise, `false.`
|
|
///
|
|
/// - SeeAlso: `elementsEqual(_:)`
|
|
% else:
|
|
/// Returns a Boolean value indicating whether this sequence and another
|
|
/// sequence contain the same elements in the same order.
|
|
///
|
|
/// At least one of the sequences must be finite.
|
|
///
|
|
/// This example tests whether one countable range shares the same elements
|
|
/// as another countable range and an array.
|
|
///
|
|
/// let a = 1...3
|
|
/// let b = 1...10
|
|
///
|
|
/// print(a.elementsEqual(b))
|
|
/// // Prints "false"
|
|
/// print(a.elementsEqual([1, 2, 3]))
|
|
/// // Prints "true"
|
|
///
|
|
/// - Parameter other: A sequence to compare to this sequence.
|
|
/// - Returns: `true` if this sequence and `other` contain the same elements
|
|
/// in the same order.
|
|
///
|
|
/// - SeeAlso: `elementsEqual(_:by:)`
|
|
% end
|
|
public func elementsEqual<OtherSequence>(
|
|
_ other: OtherSequence${"," if preds else ""}
|
|
% if preds:
|
|
by areEquivalent: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> Bool
|
|
where
|
|
OtherSequence: Sequence,
|
|
OtherSequence.${GElement} == ${GElement} {
|
|
|
|
var iter1 = self.makeIterator()
|
|
var iter2 = other.makeIterator()
|
|
while true {
|
|
switch (iter1.next(), iter2.next()) {
|
|
case let (e1?, e2?):
|
|
if ${'try !areEquivalent(e1, e2)' if preds else 'e1 != e2'} {
|
|
return false
|
|
}
|
|
case (_?, nil),
|
|
(nil, _?):
|
|
return false
|
|
case (nil, nil):
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// lexicographicallyPrecedes()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # Comparable requirement.
|
|
% for preds in [True, False]:
|
|
% rethrows_ = "rethrows " if preds else ""
|
|
|
|
extension Sequence ${"" if preds else "where Iterator.Element : Comparable"} {
|
|
|
|
% if preds:
|
|
/// Returns a Boolean value indicating whether the sequence precedes another
|
|
/// sequence in a lexicographical (dictionary) ordering, using the given
|
|
/// predicate to compare elements.
|
|
///
|
|
${orderingExplanation}
|
|
/// - Parameters:
|
|
/// - other: A sequence to compare to this sequence.
|
|
/// - areInIncreasingOrder: A predicate that returns `true` if its first
|
|
/// argument should be ordered before its second argument; otherwise,
|
|
/// `false`.
|
|
/// - Returns: `true` if this sequence precedes `other` in a dictionary
|
|
/// ordering as ordered by `areInIncreasingOrder`; otherwise, `false`.
|
|
///
|
|
/// - Note: This method implements the mathematical notion of lexicographical
|
|
/// ordering, which has no connection to Unicode. If you are sorting
|
|
/// strings to present to the end user, use `String` APIs that perform
|
|
/// localized comparison instead.
|
|
/// - SeeAlso: `lexicographicallyPrecedes(_:)`
|
|
% else:
|
|
/// Returns a Boolean value indicating whether the sequence precedes another
|
|
/// sequence in a lexicographical (dictionary) ordering, using the
|
|
/// less-than operator (`<`) to compare elements.
|
|
///
|
|
/// This example uses the `lexicographicallyPrecedes` method to test which
|
|
/// array of integers comes first in a lexicographical ordering.
|
|
///
|
|
/// let a = [1, 2, 2, 2]
|
|
/// let b = [1, 2, 3, 4]
|
|
///
|
|
/// print(a.lexicographicallyPrecedes(b))
|
|
/// // Prints "true"
|
|
/// print(b.lexicographicallyPrecedes(b))
|
|
/// // Prints "false"
|
|
///
|
|
/// - Parameter other: A sequence to compare to this sequence.
|
|
/// - Returns: `true` if this sequence precedes `other` in a dictionary
|
|
/// ordering; otherwise, `false`.
|
|
///
|
|
/// - Note: This method implements the mathematical notion of lexicographical
|
|
/// ordering, which has no connection to Unicode. If you are sorting
|
|
/// strings to present to the end user, use `String` APIs that
|
|
/// perform localized comparison.
|
|
/// - SeeAlso: `lexicographicallyPrecedes(_:by:)`
|
|
% end
|
|
public func lexicographicallyPrecedes<OtherSequence>(
|
|
_ other: OtherSequence${"," if preds else ""}
|
|
% if preds:
|
|
by areInIncreasingOrder:
|
|
(${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> Bool
|
|
where
|
|
OtherSequence : Sequence,
|
|
OtherSequence.${GElement} == ${GElement} {
|
|
|
|
var iter1 = self.makeIterator()
|
|
var iter2 = other.makeIterator()
|
|
while true {
|
|
if let e1 = iter1.next() {
|
|
if let e2 = iter2.next() {
|
|
if ${"try areInIncreasingOrder(e1, e2)" if preds else "e1 < e2"} {
|
|
return true
|
|
}
|
|
if ${"try areInIncreasingOrder(e2, e1)" if preds else "e2 < e1"} {
|
|
return false
|
|
}
|
|
continue // Equivalent
|
|
}
|
|
return false
|
|
}
|
|
|
|
return iter2.next() != nil
|
|
}
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// contains()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension Sequence where Iterator.Element : Equatable {
|
|
/// Returns a Boolean value indicating whether the sequence contains the
|
|
/// given element.
|
|
///
|
|
/// This example checks to see whether a favorite actor is in an array
|
|
/// storing a movie's cast.
|
|
///
|
|
/// let cast = ["Vivien", "Marlon", "Kim", "Karl"]
|
|
/// print(cast.contains("Marlon"))
|
|
/// // Prints "true"
|
|
/// print(cast.contains("James"))
|
|
/// // Prints "false"
|
|
///
|
|
/// - Parameter element: The element to find in the sequence.
|
|
/// - Returns: `true` if the element was found in the sequence; otherwise,
|
|
/// `false`.
|
|
public func contains(_ element: ${GElement}) -> Bool {
|
|
if let result = _customContainsEquatableElement(element) {
|
|
return result
|
|
}
|
|
|
|
for e in self {
|
|
if e == element {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
extension Sequence {
|
|
/// Returns a Boolean value indicating whether the sequence contains an
|
|
/// element that satisfies the given predicate.
|
|
///
|
|
/// You can use the predicate to check for an element of a type that
|
|
/// doesn't conform to the `Equatable` protocol, such as the
|
|
/// `HTTPResponse` enumeration in this example.
|
|
///
|
|
/// enum HTTPResponse {
|
|
/// case ok
|
|
/// case error(Int)
|
|
/// }
|
|
///
|
|
/// let lastThreeResponses: [HTTPResponse] = [.ok, .ok, .error(404)]
|
|
/// let hadError = lastThreeResponses.contains { element in
|
|
/// if case .error = element {
|
|
/// return true
|
|
/// } else {
|
|
/// return false
|
|
/// }
|
|
/// }
|
|
/// // 'hadError' == true
|
|
///
|
|
/// Alternatively, a predicate can be satisfied by a range of `Equatable`
|
|
/// elements or a general condition. This example shows how you can check an
|
|
/// array for an expense greater than $100.
|
|
///
|
|
/// let expenses = [21.37, 55.21, 9.32, 10.18, 388.77, 11.41]
|
|
/// let hasBigPurchase = expenses.contains { $0 > 100 }
|
|
/// // 'hasBigPurchase' == true
|
|
///
|
|
/// - Parameter predicate: A closure that takes an element of the sequence
|
|
/// as its argument and returns a Boolean value that indicates whether
|
|
/// the passed element represents a match.
|
|
/// - Returns: `true` if the sequence contains an element that satisfies
|
|
/// `predicate`; otherwise, `false`.
|
|
public func contains(
|
|
where predicate: (${GElement}) throws -> Bool
|
|
) rethrows -> Bool {
|
|
for e in self {
|
|
if try predicate(e) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// reduce()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension Sequence {
|
|
/// Returns the result of combining the elements of the sequence using the
|
|
/// given closure.
|
|
///
|
|
/// Use the `reduce(_:_:)` method to produce a single value from the elements
|
|
/// of an entire sequence. For example, you can use this method on an array
|
|
/// of numbers to find their sum or product.
|
|
///
|
|
/// The `nextPartialResult` closure is called sequentially with an
|
|
/// accumulating value initialized to `initialResult` and each element of
|
|
/// the sequence. This example shows how to find the sum of an array of
|
|
/// numbers.
|
|
///
|
|
/// let numbers = [1, 2, 3, 4]
|
|
/// let numberSum = numbers.reduce(0, { x, y in
|
|
/// x + y
|
|
/// })
|
|
/// // numberSum == 10
|
|
///
|
|
/// When `numbers.reduce(_:_:)` is called, the following steps occur:
|
|
///
|
|
/// 1. The `nextPartialResult` closure is called with `initialResult`---`0`
|
|
/// in this case---and the first element of `numbers`, returning the sum:
|
|
/// `1`.
|
|
/// 2. The closure is called again repeatedly with the previous call's return
|
|
/// value and each element of the sequence.
|
|
/// 3. When the sequence is exhausted, the last value returned from the
|
|
/// closure is returned to the caller.
|
|
///
|
|
/// If the sequence has no elements, `nextPartialResult` is never executed
|
|
/// and `initialResult` is the result of the call to `reduce(_:_:)`.
|
|
///
|
|
/// - Parameters:
|
|
/// - initialResult: The value to use as the initial accumulating value.
|
|
/// `initialResult` is passed to `nextPartialResult` the first time the
|
|
/// closure is executed.
|
|
/// - nextPartialResult: A closure that combines an accumulating value and
|
|
/// an element of the sequence into a new accumulating value, to be used
|
|
/// in the next call of the `nextPartialResult` closure or returned to
|
|
/// the caller.
|
|
/// - Returns: The final accumulated value. If the sequence has no elements,
|
|
/// the result is `initialResult`.
|
|
public func reduce<Result>(
|
|
_ initialResult: Result,
|
|
_ nextPartialResult:
|
|
(_ partialResult: Result, ${GElement}) throws -> Result
|
|
) rethrows -> Result {
|
|
var accumulator = initialResult
|
|
for element in self {
|
|
accumulator = try nextPartialResult(accumulator, element)
|
|
}
|
|
return accumulator
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// reversed()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension Sequence {
|
|
/// Returns an array containing the elements of this sequence in reverse
|
|
/// order.
|
|
///
|
|
/// The sequence must be finite.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the length of the sequence.
|
|
///
|
|
/// - Returns: An array containing the elements of this sequence in
|
|
/// reverse order.
|
|
public func reversed() -> [${GElement}] {
|
|
// FIXME(performance): optimize to 1 pass? But Array(self) can be
|
|
// optimized to a memcpy() sometimes. Those cases are usually collections,
|
|
// though.
|
|
var result = Array(self)
|
|
let count = result.count
|
|
for i in 0..<count/2 {
|
|
swap(&result[i], &result[count - i - 1])
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// flatMap()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension Sequence {
|
|
/// Returns an array containing the concatenated results of calling the
|
|
/// given transformation with each element of this sequence.
|
|
///
|
|
/// Use this method to receive a single-level collection when your
|
|
/// transformation produces a sequence or collection for each element.
|
|
///
|
|
/// In this example, note the difference in the result of using `map` and
|
|
/// `flatMap` with a transformation that returns an array.
|
|
///
|
|
/// let numbers = [1, 2, 3, 4]
|
|
///
|
|
/// let mapped = numbers.map { Array(count: $0, repeatedValue: $0) }
|
|
/// // [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
|
|
///
|
|
/// let flatMapped = numbers.flatMap { Array(count: $0, repeatedValue: $0) }
|
|
/// // [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
|
|
///
|
|
/// In fact, `s.flatMap(transform)` is equivalent to
|
|
/// `Array(s.map(transform).joined())`.
|
|
///
|
|
/// - Parameter transform: A closure that accepts an element of this
|
|
/// sequence as its argument and returns a sequence or collection.
|
|
/// - Returns: The resulting flattened array.
|
|
///
|
|
/// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
|
|
/// and *n* is the length of the result.
|
|
/// - SeeAlso: `joined()`, `map(_:)`
|
|
public func flatMap<SegmentOfResult : Sequence>(
|
|
_ transform: (${GElement}) throws -> SegmentOfResult
|
|
) rethrows -> [SegmentOfResult.${GElement}] {
|
|
var result: [SegmentOfResult.${GElement}] = []
|
|
for element in self {
|
|
result.append(contentsOf: try transform(element))
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
extension Sequence {
|
|
/// Returns an array containing the non-`nil` results of calling the given
|
|
/// transformation with each element of this sequence.
|
|
///
|
|
/// Use this method to receive an array of nonoptional values when your
|
|
/// transformation produces an optional value.
|
|
///
|
|
/// In this example, note the difference in the result of using `map` and
|
|
/// `flatMap` with a transformation that returns an optional `Int` value.
|
|
///
|
|
/// let possibleNumbers = ["1", "2", "three", "///4///", "5"]
|
|
///
|
|
/// let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
|
|
/// // [1, 2, nil, nil, 5]
|
|
///
|
|
/// let flatMapped: [Int] = possibleNumbers.flatMap { str in Int(str) }
|
|
/// // [1, 2, 5]
|
|
///
|
|
/// - Parameter transform: A closure that accepts an element of this
|
|
/// sequence as its argument and returns an optional value.
|
|
/// - Returns: An array of the non-`nil` results of calling `transform`
|
|
/// with each element of the sequence.
|
|
///
|
|
/// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
|
|
/// and *n* is the length of the result.
|
|
public func flatMap<ElementOfResult>(
|
|
_ transform: (${GElement}) throws -> ElementOfResult?
|
|
) rethrows -> [ElementOfResult] {
|
|
var result: [ElementOfResult] = []
|
|
for element in self {
|
|
if let newElement = try transform(element) {
|
|
result.append(newElement)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
extension Sequence {
|
|
@available(*, unavailable, renamed: "enumerated()")
|
|
public func enumerate() -> EnumeratedSequence<Self> {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "min(by:)")
|
|
public func minElement(
|
|
_ isOrderedBefore: (Iterator.Element, Iterator.Element) throws -> Bool
|
|
) rethrows -> Iterator.Element? {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "max(by:)")
|
|
public func maxElement(
|
|
_ isOrderedBefore: (Iterator.Element, Iterator.Element) throws -> Bool
|
|
) rethrows -> Iterator.Element? {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "reversed()")
|
|
public func reverse() -> [Iterator.Element] {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "starts(with:by:)")
|
|
public func startsWith<PossiblePrefix>(
|
|
_ possiblePrefix: PossiblePrefix,
|
|
isEquivalent: (Iterator.Element, Iterator.Element) throws -> Bool
|
|
) rethrows-> Bool
|
|
where
|
|
PossiblePrefix : Sequence,
|
|
PossiblePrefix.Iterator.Element == Iterator.Element {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "elementsEqual(_:by:)")
|
|
public func elementsEqual<OtherSequence>(
|
|
_ other: OtherSequence,
|
|
isEquivalent: (${GElement}, ${GElement}) throws -> Bool
|
|
) rethrows -> Bool
|
|
where
|
|
OtherSequence: Sequence,
|
|
OtherSequence.${GElement} == ${GElement} {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "lexicographicallyPrecedes(_:by:)")
|
|
public func lexicographicalCompare<
|
|
OtherSequence
|
|
>(
|
|
_ other: OtherSequence,
|
|
isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool
|
|
) rethrows -> Bool
|
|
where
|
|
OtherSequence : Sequence,
|
|
OtherSequence.${GElement} == ${GElement} {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "contains(where:)")
|
|
public func contains(
|
|
_ predicate: (${GElement}) throws -> Bool
|
|
) rethrows -> Bool {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "reduce(_:_:)")
|
|
public func reduce<Result>(
|
|
_ initial: Result,
|
|
combine: (_ partialResult: Result, ${GElement}) throws -> Result
|
|
) rethrows -> Result {
|
|
Builtin.unreachable()
|
|
}
|
|
}
|
|
|
|
extension Sequence where Iterator.Element : Comparable {
|
|
@available(*, unavailable, renamed: "min()")
|
|
public func minElement() -> Iterator.Element? {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "max()")
|
|
public func maxElement() -> Iterator.Element? {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "starts(with:)")
|
|
public func startsWith<PossiblePrefix>(
|
|
_ possiblePrefix: PossiblePrefix
|
|
) -> Bool
|
|
where
|
|
PossiblePrefix : Sequence,
|
|
PossiblePrefix.${GElement} == ${GElement} {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "lexicographicallyPrecedes")
|
|
public func lexicographicalCompare<OtherSequence>(
|
|
_ other: OtherSequence
|
|
) -> Bool
|
|
where
|
|
OtherSequence : Sequence,
|
|
OtherSequence.${GElement} == ${GElement} {
|
|
Builtin.unreachable()
|
|
}
|
|
}
|