Unique.swift 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Algorithms open source project
  4. //
  5. // Copyright (c) 2020 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See https://swift.org/LICENSE.txt for license information
  9. //
  10. //===----------------------------------------------------------------------===//
  11. /// A sequence wrapper that leaves out duplicate elements of a base sequence.
  12. public struct UniquedSequence<Base: Sequence, Subject: Hashable> {
  13. /// The base collection.
  14. @usableFromInline
  15. internal let base: Base
  16. /// The projection function.
  17. @usableFromInline
  18. internal let projection: (Base.Element) -> Subject
  19. @usableFromInline
  20. internal init(base: Base, projection: @escaping (Base.Element) -> Subject) {
  21. self.base = base
  22. self.projection = projection
  23. }
  24. }
  25. extension UniquedSequence: Sequence {
  26. /// The iterator for a `UniquedSequence` instance.
  27. public struct Iterator: IteratorProtocol {
  28. @usableFromInline
  29. internal var base: Base.Iterator
  30. @usableFromInline
  31. internal let projection: (Base.Element) -> Subject
  32. @usableFromInline
  33. internal var seen: Set<Subject> = []
  34. @usableFromInline
  35. internal init(
  36. base: Base.Iterator,
  37. projection: @escaping (Base.Element) -> Subject
  38. ) {
  39. self.base = base
  40. self.projection = projection
  41. }
  42. @inlinable
  43. public mutating func next() -> Base.Element? {
  44. while let element = base.next() {
  45. if seen.insert(projection(element)).inserted {
  46. return element
  47. }
  48. }
  49. return nil
  50. }
  51. }
  52. @inlinable
  53. public func makeIterator() -> Iterator {
  54. Iterator(base: base.makeIterator(), projection: projection)
  55. }
  56. }
  57. extension UniquedSequence: LazySequenceProtocol
  58. where Base: LazySequenceProtocol {}
  59. //===----------------------------------------------------------------------===//
  60. // uniqued()
  61. //===----------------------------------------------------------------------===//
  62. extension Sequence where Element: Hashable {
  63. /// Returns a sequence with only the unique elements of this sequence, in the
  64. /// order of the first occurrence of each unique element.
  65. ///
  66. /// let animals = ["dog", "pig", "cat", "ox", "dog", "cat"]
  67. /// let uniqued = animals.uniqued()
  68. /// print(Array(uniqued))
  69. /// // Prints '["dog", "pig", "cat", "ox"]'
  70. ///
  71. /// - Returns: A sequence with only the unique elements of this sequence.
  72. /// .
  73. /// - Complexity: O(1).
  74. @inlinable
  75. public func uniqued() -> UniquedSequence<Self, Element> {
  76. UniquedSequence(base: self, projection: { $0 })
  77. }
  78. }
  79. extension Sequence {
  80. /// Returns an array with the unique elements of this sequence (as determined
  81. /// by the given projection), in the order of the first occurrence of each
  82. /// unique element.
  83. ///
  84. /// This example finds the elements of the `animals` array with unique
  85. /// first characters:
  86. ///
  87. /// let animals = ["dog", "pig", "cat", "ox", "cow", "owl"]
  88. /// let uniqued = animals.uniqued(on: { $0.first })
  89. /// print(uniqued)
  90. /// // Prints '["dog", "pig", "cat", "ox"]'
  91. ///
  92. /// - Parameter projection: A closure that transforms an element into the
  93. /// value to use for uniqueness. If `projection` returns the same value for
  94. /// two different elements, the second element will be excluded from the
  95. /// resulting array.
  96. ///
  97. /// - Returns: An array with only the unique elements of this sequence, as
  98. /// determined by the result of `projection` for each element.
  99. ///
  100. /// - Complexity: O(*n*), where *n* is the length of the sequence.
  101. @inlinable
  102. public func uniqued<Subject: Hashable>(
  103. on projection: (Element) throws -> Subject
  104. ) rethrows -> [Element] {
  105. var seen: Set<Subject> = []
  106. var result: [Element] = []
  107. for element in self {
  108. if seen.insert(try projection(element)).inserted {
  109. result.append(element)
  110. }
  111. }
  112. return result
  113. }
  114. }
  115. //===----------------------------------------------------------------------===//
  116. // lazy.uniqued()
  117. //===----------------------------------------------------------------------===//
  118. extension LazySequenceProtocol {
  119. /// Returns a lazy sequence with the unique elements of this sequence (as
  120. /// determined by the given projection), in the order of the first occurrence
  121. /// of each unique element.
  122. ///
  123. /// - Complexity: O(1).
  124. @inlinable
  125. public func uniqued<Subject: Hashable>(
  126. on projection: @escaping (Element) -> Subject
  127. ) -> UniquedSequence<Self, Subject> {
  128. UniquedSequence(base: self, projection: projection)
  129. }
  130. }