//===--- 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 http://swift.org/LICENSE.txt for license information // See http://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'" /// /// - 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: @noescape (${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: @noescape (${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`. Returns /// `true` if `possiblePrefix` has no elements. /// /// - 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. /// /// For example: /// /// let a = 1...3 /// let b = 1...10 /// /// print(b.starts(with: a)) /// // Prints "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`. Returns `true` /// if `possiblePrefix` has no elements. /// /// - SeeAlso: `starts(with:by:)` % end public func starts( with possiblePrefix: PossiblePrefix${"," if preds else ""} % if preds: by areEquivalent: @noescape (${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 the sequence and a given /// 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 the sequence and a given /// sequence contain the same elements in the same order. /// /// At least one of the sequences must be finite. /// /// For example: /// /// 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: @noescape (${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. /// /// For example: /// /// 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, you should use `String` APIs that /// perform localized comparison. /// - SeeAlso: `lexicographicallyPrecedes(_:by:)` % end public func lexicographicallyPrecedes( _ other: OtherSequence${"," if preds else ""} % if preds: by areInIncreasingOrder: @noescape (${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: @noescape (${GElement}) throws -> Bool ) rethrows -> Bool { for e in self { if try predicate(e) { return true } } return false } } //===----------------------------------------------------------------------===// // reduce() //===----------------------------------------------------------------------===// extension Sequence { /// Returns the result of calling the given combining closure with each /// element of this sequence and an accumulating value. /// /// The `combine` closure is called sequentially with an accumulating /// value initialized to `initial` 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 addTwo: (Int, Int) -> Int = { x, y in x + y } /// let numberSum = numbers.reduce(0, combine: addTwo) /// // 'numberSum' == 10 /// /// When `numbers.reduce(_:combine:)` is called, the following steps /// occur: /// /// 1. The `combine` closure is called with the initial value 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. /// /// - Parameters: /// - initial: A value to use as the initial value for accumulation. /// - combine: 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 `combine` closure or returned to the /// caller. /// - Returns: The final accumulated value. public func reduce( _ initial: T, combine: @noescape (T, ${GElement}) throws -> T ) rethrows -> T { var result = initial for element in self { result = try combine(result, element) } return result } } //===----------------------------------------------------------------------===// // 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: @noescape (${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?] = numbers.map { str in Int(str) } /// // [1, 2, nil, nil, 5] /// /// let flatMapped: [Int] = numbers.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: @noescape (${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: @noescape (Iterator.Element, Iterator.Element) throws -> Bool ) rethrows -> Iterator.Element? { Builtin.unreachable() } @available(*, unavailable, renamed: "max(by:)") public func maxElement( _ isOrderedBefore: @noescape (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: @noescape (Iterator.Element, Iterator.Element) throws -> Bool ) rethrows-> Bool where PossiblePrefix : Sequence, PossiblePrefix.Iterator.Element == Iterator.Element { Builtin.unreachable() } @available(*, unavailable, renamed: "lexicographicallyPrecedes(_:by:)") public func lexicographicalCompare< OtherSequence >( _ other: OtherSequence, isOrderedBefore: @noescape (${GElement}, ${GElement}) throws -> Bool ) rethrows -> Bool where OtherSequence : Sequence, OtherSequence.${GElement} == ${GElement} { 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() } }