Home > Mobile >  Intersection of ranges (of floating point ranges)
Intersection of ranges (of floating point ranges)

Time:11-12

I am asking a user for four ranges of floating point numbers. I want to check that there is no overlap between them.

If the ranges were integer ranges it seems that I could either create sets or use Swift Range (or NSRange) and check for intersections.

Is there a way to figure this out if the ranges where then upper and lower bounds are floating point values?

Would I just have to check that each lower and upper bound of each range is not between the lower/upper bound of each of the other ranges? Is there a better way?

Thanks

CodePudding user response:

You can use the Range type to represent a range of floating point values. You can then use the contains method to check if a value is in a range. You can also use the overlaps method to check if two ranges overlap. Here is an example:

let range1 = 1.0..<2.0
let range2 = 1.5..<3.0
let range3 = 2.0..<4.0

range1.contains(1.5) // true
range1.overlaps(range2) // true
range1.overlaps(range3) // false

You can also use the ~= operator to check if a value is in a range. This is the same operator that is used in switch statements.

let value = 1.5
switch value {
case range1:
    if range1.contains(value) {
        print("value is in range1")
    }
case range2:
    if range2.contains(value) {
        print("value is in range2")
    }
case range3:
    if range3.contains(value) {
        print("value is in range3")
    }
default:
    print("value is not in any range")
}

You can use the sorted method to sort an array of ranges. Here is an example:

let ranges = [range1, range2, range3]
let sortedRanges = ranges.sorted { $0.lowerBound < $1.lowerBound }

You can then iterate over the sorted ranges and check if the upper bound of the previous range is greater than the lower bound of the current range.

for (index, range) in sortedRanges.enumerated() {
    if index > 0 {
        let previousRange = sortedRanges[index - 1]
        if previousRange.upperBound > range.lowerBound {
            print("ranges overlap")
        }
    }
}

You can also use the contains/overlaps method to check if a range contains another range.

for (index, range) in sortedRanges.enumerated() {
    if index > 0 {
        let previousRange = sortedRanges[index - 1]
        if range.contains(previousRange) {
            print("ranges overlap")
        }
        if range.overlaps(previousRange) {
            print("ranges overlap")
        }
    }
}

CodePudding user response:

There is no way to express it as a property yet; it has to be a function.

import Algorithms

extension Sequence {
  func containsAnOverlap<Bound>() -> Bool
  where Element == ClosedRange<Bound> {
    sorted(by: \.lowerBound).adjacentPairs().contains { $0.overlaps($1) }
  }
}

public extension Sequence {
  /// Sorted by a common `Comparable` value.
  func sorted(
    by comparable: (Element) throws -> some Comparable
  ) rethrows -> [Element] {
    try sorted(by: comparable, <)
  }

  /// Sorted by a common `Comparable` value, and sorting closure.
  func sorted<Comparable: Swift.Comparable>(
    by comparable: (Element) throws -> Comparable,
    _ areInIncreasingOrder: (Comparable, Comparable) throws -> Bool
  ) rethrows -> [Element] {
    try sorted {
      try areInIncreasingOrder(comparable($0), comparable($1))
    }
  }
}
[2...3.0, 0...1.0].containsAnOverlap() // false
[1...3.0, 0...2.0].containsAnOverlap() // true
  • Related