Collection.swift 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. //
  2. // Collection.swift
  3. // LoopKit
  4. //
  5. // Created by Michael Pangburn on 2/14/19.
  6. // Copyright © 2019 LoopKit Authors. All rights reserved.
  7. //
  8. /// Returns the cartesian product of a sequence and a collection.
  9. ///
  10. /// O(1), but O(_n_*_m_) on iteration.
  11. /// - Note: Don't mind the scary return type; it's just a lazy sequence.
  12. func product<S: Sequence, C: Collection>(_ s: S, _ c: C) -> LazySequence<FlattenSequence<LazyMapSequence<S, LazyMapSequence<C, (S.Element, C.Element)>>>> {
  13. return s.lazy.flatMap { first in
  14. c.lazy.map { second in
  15. (first, second)
  16. }
  17. }
  18. }
  19. extension Collection {
  20. /// Returns a sequence containing adjacent pairs of elements in the ordered collection.
  21. func adjacentPairs() -> Zip2Sequence<Self, SubSequence> {
  22. return zip(self, dropFirst())
  23. }
  24. }
  25. extension Collection {
  26. func chunked(into size: Int) -> [SubSequence] {
  27. precondition(size > 0, "Chunk size must be greater than zero")
  28. var start = startIndex
  29. return stride(from: 0, to: count, by: size).map {_ in
  30. let end = index(start, offsetBy: size, limitedBy: endIndex) ?? endIndex
  31. defer { start = end }
  32. return self[start..<end]
  33. }
  34. }
  35. }
  36. extension RandomAccessCollection {
  37. /// Returns all unique pair combinations of elements in the collection.
  38. ///
  39. /// O(1), but O(*n*²) on iteration.
  40. /// - Note: Don't mind the scary return type; it's just a lazy sequence.
  41. func allPairs() -> LazyMapSequence<LazyFilterSequence<FlattenSequence<LazyMapSequence<Indices, LazyMapSequence<Indices, (Index, Index)>>>>, (Element, Element)> {
  42. return product(indices, indices).filter(<).map {
  43. (self[$0], self[$1])
  44. }
  45. }
  46. }
  47. extension RangeReplaceableCollection where Index: Hashable {
  48. /// Removes the elements at all of the given indices.
  49. ///
  50. /// O(_n_*_m_)
  51. mutating func removeAll<S: Sequence>(at indices: S) where S.Element == Index {
  52. let arranged = Set(indices).sorted(by: >)
  53. for index in arranged {
  54. remove(at: index)
  55. }
  56. }
  57. }
  58. // Source: https://github.com/apple/swift/blob/master/stdlib/public/core/CollectionAlgorithms.swift#L476
  59. extension Collection {
  60. /// Returns the index of the first element in the collection that matches
  61. /// the predicate.
  62. ///
  63. /// The collection must already be partitioned according to the predicate.
  64. /// That is, there should be an index `i` where for every element in
  65. /// `collection[..<i]` the predicate is `false`, and for every element
  66. /// in `collection[i...]` the predicate is `true`.
  67. ///
  68. /// - Parameter predicate: A predicate that partitions the collection.
  69. /// - Returns: The index of the first element in the collection for which
  70. /// `predicate` returns `true`.
  71. ///
  72. /// - Complexity: O(log *n*), where *n* is the length of this collection if
  73. /// the collection conforms to `RandomAccessCollection`, otherwise O(*n*).
  74. func partitioningIndex(
  75. where predicate: (Element) throws -> Bool
  76. ) rethrows -> Index {
  77. var n = count
  78. var l = startIndex
  79. while n > 0 {
  80. let half = n / 2
  81. let mid = index(l, offsetBy: half)
  82. if try predicate(self[mid]) {
  83. n = half
  84. } else {
  85. l = index(after: mid)
  86. n -= half + 1
  87. }
  88. }
  89. return l
  90. }
  91. }