//===--- 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] = [] /// 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 { 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( 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( _ 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( _ 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( _ 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..( _ 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( _ 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 { 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, 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( _ 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( _ 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 ) -> Bool where PossiblePrefix : Sequence, PossiblePrefix.${GElement} == ${GElement} { Builtin.unreachable() } @available(*, unavailable, renamed: "lexicographicallyPrecedes") public func lexicographicalCompare( _ other: OtherSequence ) -> Bool where OtherSequence : Sequence, OtherSequence.${GElement} == ${GElement} { Builtin.unreachable() } }