0

I have searched around trying to find a similar problem, however I do not know the correct wording. I have an array of CGFloats and then a separate saved CGFloat. I want to check if the single CGFloat is between the values stored in the array.

I currently have this in a loop starting at the end of the array and checking if it is smaller than the value. It then moves from right to left until it is not smaller and returns the index. Is there a built in method or a cleaner way to do this?

For example:

var pressureLevels:[CGFloat] = [0, 1.0, 2.133333333333333, 3.266666666666667, 4.4, 5.533333333333334, 6.666666666666667]

var tempPressure: CGFloat = 4.877777

return 4 or return 5

I want to be able to tell that tempPressure is in pressureLevels between 4.4 and 5.533333333333334 and return the index (either 4 or 5).

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • Are you looking for a *binary search?* Then this https://stackoverflow.com/q/26678362/1187415 might be helpful. – Martin R Jan 03 '19 at 17:31
  • Google binary search, i.e. search for an element in an monotonically increasing or decreasing array. – joeybladb Jan 03 '19 at 17:35

2 Answers2

1

This will return the higher index, for the next larger value. I have assumed from your example that the array is already sorted

let largerIndex  = pressureLevels.firstIndex(where: { $0 > tempPressure}) 
let smallerIndex = largerIndex - 1

Note the edge cases, if there is no value larger than tempPressure then largerIndex will be nil and if all values in the array are larger then largerIndex will be 0

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • 1
    `largerIndex will be set to pressureLevels.count` that's bad design. Don't use magic values to model failures. Use `nil` instead. – Alexander Jan 03 '19 at 19:25
0

Joakim Danielson's way will work fine for sorted arrays. If your array is unsorted you could put the logic in an extension of the Array class like so:

extension Array where Element == CGFloat {
    func huggingIndexes(for value:CGFloat) -> (lower:Int?, upper:Int?) {
        var largestLowerBound:CGFloat?
        var lowerIndex:Int?
        var smallestUpperBound:CGFloat?
        var upperIndex:Int?

        for (index, val) in self.enumerated() {

            if val < value, val >= largestLowerBound ?? val {
                largestLowerBound = val
                lowerIndex = index
            } else if val > value, val <= smallestUpperBound ?? val {
                smallestUpperBound = val
                upperIndex = index
            }

        }

        return (lowerIndex, upperIndex)
    }
}

var pressureLevels:[CGFloat] = [2.133333333333333, 4.4, 6.666666666666667, 1.0, 5.533333333333334, 0.0, 3.266666666666667]

var tempPressure: CGFloat = 4.877777

let huggingIndexes = pressureLevels.huggingIndexes(for: tempPressure)

print(huggingIndexes.lower) //Prints 1
print(huggingIndexes.upper) //Prints 4
levidhuyvetter
  • 401
  • 5
  • 16