forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSequenceAlgorithms.swift.gyb
777 lines (733 loc) · 27.7 KB
/
SequenceAlgorithms.swift.gyb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
//===--- SequenceAlgorithms.swift.gyb -------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
%{
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".enumerated() {
/// print("\(n): '\(c)'")
/// }
/// // Prints "0: 'S'"
/// // Prints "1: 'w'"
/// // Prints "2: 'i'"
/// // Prints "3: 'f'"
/// // Prints "4: 't'"
///
/// When you enumerate a collection, the integer part of each pair is a counter
/// for the enumeration, but is not necessarily the index of the paired value.
/// These counters can be used as indices only 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 consisting 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.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.
@_inlineable
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 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`.
% 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`.
% end
@_inlineable
@warn_unqualified_access
public func min(
% if preds:
by areInIncreasingOrder: (Element, Element) throws -> Bool
% end
) ${rethrows_}-> Element? {
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`.
% else:
/// Returns the maximum element in the sequence.
///
/// This example finds the largest 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`.
% end
@_inlineable
@warn_unqualified_access
public func max(
% if preds:
by areInIncreasingOrder: (Element, Element) throws -> Bool
% end
) ${rethrows_}-> Element? {
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 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`.
% 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`.
% end
@_inlineable
public func starts<PossiblePrefix>(
with possiblePrefix: PossiblePrefix${"," if preds else ""}
% if preds:
by areEquivalent: (Element, Element) throws -> Bool
% end
) ${rethrows_}-> Bool
where
PossiblePrefix : Sequence,
PossiblePrefix.Element == Element {
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 Element : Equatable"} {
% if preds:
/// Returns a Boolean value indicating whether this sequence and another
/// sequence contain equivalent elements in the same order, 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.`
% 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.
% end
@_inlineable
public func elementsEqual<OtherSequence>(
_ other: OtherSequence${"," if preds else ""}
% if preds:
by areEquivalent: (Element, OtherSequence.Element) throws -> Bool
% end
) ${rethrows_}-> Bool
where
OtherSequence: Sequence${" {" if preds else ","}
% if not preds:
OtherSequence.Element == Element {
% end
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 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.
% 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.
% end
@_inlineable
public func lexicographicallyPrecedes<OtherSequence>(
_ other: OtherSequence${"," if preds else ""}
% if preds:
by areInIncreasingOrder:
(Element, Element) throws -> Bool
% end
) ${rethrows_}-> Bool
where
OtherSequence : Sequence,
OtherSequence.Element == Element {
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 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`.
@_inlineable
public func contains(_ element: Element) -> 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`.
@_inlineable
public func contains(
where predicate: (Element) 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`.
@_inlineable
public func reduce<Result>(
_ initialResult: Result,
_ nextPartialResult:
(_ partialResult: Result, Element) throws -> Result
) rethrows -> Result {
var accumulator = initialResult
for element in self {
accumulator = try nextPartialResult(accumulator, element)
}
return accumulator
}
/// Returns the result of combining the elements of the sequence using the
/// given closure.
///
/// Use the `reduce(into:_:)` method to produce a single value from the
/// elements of an entire sequence. For example, you can use this method on an
/// array of integers to filter adjacent equal entries or count frequencies.
///
/// This method is preferred over `reduce(_:_:)` for efficiency when the
/// result is a copy-on-write type, for example an Array or a Dictionary.
///
/// The `updateAccumulatingResult` closure is called sequentially with a
/// mutable accumulating value initialized to `initialResult` and each element
/// of the sequence. This example shows how to build a dictionary of letter
/// frequencies of a string.
///
/// let letters = "abracadabra"
/// let letterCount = letters.reduce(into: [:]) { counts, letter in
/// counts[letter, default: 0] += 1
/// }
/// // letterCount == ["a": 5, "b": 2, "r": 2, "c": 1, "d": 1]
///
/// When `letters.reduce(into:_:)` is called, the following steps occur:
///
/// 1. The `updateAccumulatingResult` closure is called with the initial
/// accumulating value---`[:]` in this case---and the first character of
/// `letters`, modifying the accumulating value by setting `1` for the key
/// `"a"`.
/// 2. The closure is called again repeatedly with the updated accumulating
/// value and each element of the sequence.
/// 3. When the sequence is exhausted, the accumulating value is returned to
/// the caller.
///
/// If the sequence has no elements, `updateAccumulatingResult` is never
/// executed and `initialResult` is the result of the call to
/// `reduce(into:_:)`.
///
/// - Parameters:
/// - initialResult: The value to use as the initial accumulating value.
/// - updateAccumulatingResult: A closure that updates the accumulating
/// value with an element of the sequence.
/// - Returns: The final accumulated value. If the sequence has no elements,
/// the result is `initialResult`.
@_inlineable
public func reduce<Result>(
into initialResult: Result,
_ updateAccumulatingResult:
(_ partialResult: inout Result, Element) throws -> ()
) rethrows -> Result {
var accumulator = initialResult
for element in self {
try updateAccumulatingResult(&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.
@_inlineable
public func reversed() -> [Element] {
// 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 {
result.swapAt(i, count - ((i + 1) as Int))
}
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.
@_inlineable
public func flatMap<SegmentOfResult : Sequence>(
_ transform: (Element) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.Element] {
var result: [SegmentOfResult.Element] = []
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.
@_inlineable
public func flatMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
return try _flatMap(transform)
}
// The implementation of flatMap accepting a closure with an optional result.
// Factored out into a separate functions in order to be used in multiple
// overloads.
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public func _flatMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
var result: [ElementOfResult] = []
for element in self {
if let newElement = try transform(element) {
result.append(newElement)
}
}
return result
}
}