Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detection of How One Sorted Sequence Includes Another #38

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename the methods
Change the name of the "sortedOverlap" methods to "degreeOfInclusion," to clarify what is being calculated.
  • Loading branch information
CTMacUser committed Mar 19, 2022
commit eb2a4984495089712e1c5d590800d3f02178f135
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -10,9 +10,9 @@ This project follows semantic versioning.

### Additions

- The `sortedOverlap(with: by:)` and `sortedOverlap(with:)` methods have been
added. They report how much overlap two sorted sequences have, expressed by
the new `SetInclusion` type. ([#38])
- The `degreeOfInclusion(with:by:)` and `degreeOfInclusion(with:)` methods have
been added. They report how much overlap two sorted sequences have, expressed
by the `SetInclusion` type. ([#38])

---

12 changes: 6 additions & 6 deletions Guides/SortedInclusion.md
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
Methods to find how much two sorted sequences overlap.

```swift
if (1...7).sortedOverlap(with: [1, 5, 6]).doesFirstIncludeSecond {
if (1...7).degreeOfInclusion(with: [1, 5, 6]).doesFirstIncludeSecond {
print("The range is a superset of the array.")
}
```
@@ -43,14 +43,14 @@ extension SetInclusion {
}

extension Sequence {
func sortedOverlap<S: Sequence>(
func degreeOfInclusion<S: Sequence>(
with other: S,
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> SetInclusion where S.Element == Element
}

extension Sequence where Element: Comparable {
func sortedOverlap<S: Sequence>(
func degreeOfInclusion<S: Sequence>(
with other: S
) -> SetInclusion where S.Element == Element
}
@@ -64,11 +64,11 @@ O(_n_) operations, where _n_ is the length of the shorter source.
### Comparison with other languages

**C++:** The `<algorithm>` library defines the `includes` function, whose
functionality is part of the semantics of `sortedOverlap`. The `includes`
functionality is part of the semantics of `degreeOfInclusion`. The `includes`
function only detects of the second sequence is included within the first; it
doesn't notify if the inclusion is degenerate, or if inclusion fails because
it's actually reversed, both of which `sortedOverlap` can do. To get the
it's actually reversed, both of which `degreeOfInclusion` can do. To get the
direct functionality of `includes`, check the `doesFirstIncludeSecond` property
of the return value from `sortedOverlap`.
of the return value from `degreeOfInclusion`.

(To-do: add other languages.)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ Read more about the package, and the intent behind it, in the [announcement on s
- [`reductions(_:)`, `reductions(_:_:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Reductions.md): Returns all the intermediate states of reducing the elements of a sequence or collection.
- [`split(maxSplits:omittingEmptySubsequences:whereSeparator)`, `split(separator:maxSplits:omittingEmptySubsequences)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Split.md): Lazy versions of the Standard Library's eager operations that split sequences and collections into subsequences separated by the specified separator element.
- [`windows(ofCount:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Windows.md): Breaks a collection into overlapping subsequences where elements are slices from the original collection.
- [`sortedOverlap(with:by:)`, `sortedOverlap(with:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/SortedInclusion.md): Reports the degree two sorted sequences overlap.
- [`degreeOfInclusion(with:by:)`, `degreeOfInclusion(with:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/SortedInclusion.md): Reports the degree two sorted sequences overlap.

## Adding Swift Algorithms as a Dependency

10 changes: 5 additions & 5 deletions Sources/Algorithms/SortedInclusion.swift
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ extension SetInclusion {
}

//===----------------------------------------------------------------------===//
// sortedOverlap(with: by:)
// degreeOfInclusion(with:by:)
//===----------------------------------------------------------------------===//

extension Sequence {
@@ -79,7 +79,7 @@ extension Sequence {
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of the
/// sequence and the length of `other`.
public func sortedOverlap<S: Sequence>(
public func degreeOfInclusion<S: Sequence>(
with other: S,
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> SetInclusion where S.Element == Element {
@@ -117,7 +117,7 @@ extension Sequence {
}

//===----------------------------------------------------------------------===//
// sortedOverlap(with:)
// degreeOfInclusion(with:)
//===----------------------------------------------------------------------===//

extension Sequence where Element: Comparable {
@@ -135,8 +135,8 @@ extension Sequence where Element: Comparable {
/// - Complexity: O(*m*), where *m* is the lesser of the length of the
/// sequence and the length of `other`.
@inlinable
public func sortedOverlap<S: Sequence>(with other: S) -> SetInclusion
public func degreeOfInclusion<S: Sequence>(with other: S) -> SetInclusion
where S.Element == Element {
return sortedOverlap(with: other, by: <)
return degreeOfInclusion(with: other, by: <)
}
}
24 changes: 12 additions & 12 deletions Tests/SwiftAlgorithmsTests/SortedInclusionTests.swift
Original file line number Diff line number Diff line change
@@ -46,56 +46,56 @@ final class SortedInclusionTests: XCTestCase {
/// Check when both sources are empty.
func testEmpty() {
let empty = EmptyCollection<Int>()
XCTAssertEqual(empty.sortedOverlap(with: empty), .bothUninhabited)
XCTAssertEqual(empty.degreeOfInclusion(with: empty), .bothUninhabited)
}

/// Check when exactly one source is empty.
func testOnlyOneEmpty() {
let empty = EmptyCollection<Int>(), single = CollectionOfOne(1)
XCTAssertEqual(single.sortedOverlap(with: empty), .onlyFirstInhabited)
XCTAssertEqual(empty.sortedOverlap(with: single), .onlySecondInhabited)
XCTAssertEqual(single.degreeOfInclusion(with: empty), .onlyFirstInhabited)
XCTAssertEqual(empty.degreeOfInclusion(with: single), .onlySecondInhabited)
}

/// Check when there are no common elements.
func testDisjoint() {
let one = CollectionOfOne(1), two = CollectionOfOne(2)
XCTAssertEqual(one.sortedOverlap(with: two), .dualExclusivesOnly)
XCTAssertEqual(two.sortedOverlap(with: one), .dualExclusivesOnly)
XCTAssertEqual(one.degreeOfInclusion(with: two), .dualExclusivesOnly)
XCTAssertEqual(two.degreeOfInclusion(with: one), .dualExclusivesOnly)
// The order changes which comparison branch is used and which versus-nil
// case is used.
}

/// Check when there are only common elements.
func testIdentical() {
let single = CollectionOfOne(1)
XCTAssertEqual(single.sortedOverlap(with: single), .sharedOnly)
XCTAssertEqual(single.degreeOfInclusion(with: single), .sharedOnly)
}

/// Check when the first source is a superset of the second.
func testFirstIncludesSecond() {
XCTAssertEqual([1, 2, 3, 5, 7].sortedOverlap(with: [1, 3, 5, 7]),
XCTAssertEqual([1, 2, 3, 5, 7].degreeOfInclusion(with: [1, 3, 5, 7]),
.firstExtendsSecond)
XCTAssertEqual([2, 4, 6, 8].sortedOverlap(with: [2, 4, 6]),
XCTAssertEqual([2, 4, 6, 8].degreeOfInclusion(with: [2, 4, 6]),
.firstExtendsSecond)
// The logic path differs if the last elements tie, or the first source's
// last element is bigger. (The second's last element can't be biggest.)
}

/// Check when the second source is a superset of the first.
func testSecondIncludesFirst() {
XCTAssertEqual([1, 3, 5, 7].sortedOverlap(with: [1, 2, 3, 5, 7]),
XCTAssertEqual([1, 3, 5, 7].degreeOfInclusion(with: [1, 2, 3, 5, 7]),
.secondExtendsFirst)
XCTAssertEqual([2, 4, 6].sortedOverlap(with: [2, 4, 6, 8]),
XCTAssertEqual([2, 4, 6].degreeOfInclusion(with: [2, 4, 6, 8]),
.secondExtendsFirst)
// The logic path differs if the last elements tie, or the second source's
// last element is bigger. (The first's last element can't be biggest.)
}

/// Check when there are shared and two-way exclusive elements.
func testPartialOverlap() {
XCTAssertEqual([3, 6, 9].sortedOverlap(with: [2, 4, 6, 8]),
XCTAssertEqual([3, 6, 9].degreeOfInclusion(with: [2, 4, 6, 8]),
.dualExclusivesAndShared)
XCTAssertEqual([1, 2, 4].sortedOverlap(with: [1, 4, 16]),
XCTAssertEqual([1, 2, 4].degreeOfInclusion(with: [1, 4, 16]),
.dualExclusivesAndShared)
// For the three categories; exclusive to first, exclusive to second, and
// shared; if the third one encountered isn't from the last element(s) from