0

I have a large array of (x,y) pairs:

 P = 

   [
    (0.0, 500000.09999999998), 
    (0.001, 18.332777589999999), 
    (0.002, 18.332221480000001), 
    (0.0030000000000000001, 18.331665000000001), 
    (0.0040000000000000001, 18.331108140000001), 
    (0.0050000000000000001, 18.33055092), 
    (0.0060000000000000001, 18.32999332), 
    ...
    ]

I now need to use this in my code. I need to search for a specific x-value and, if the x-value exists, return its corresponding y-value.

Note: If there is a better format I could put my (x,y) pairs in, please feel free to let me know. For example, 2 separate arrays where one holds the x-values and the other holds the y-values. Then I could use the index to find the corresponding y-value or something.


Edit:

A user made a very good point in the comments: how can I reliably compare x == 0.001?

The way I will be using my code is this: I am evaluating a function f(x) at values of x. However, if at a particular value of x there is a y value in the P array, then I need to do an extra subtraction calculation (the details of which are not too important here). The problem, then, is that what if I pass the x value 0.001 in there and the P array does not have a correpsonding y value, but it does have one for 0.001000000009?? Then the code will say there is no value, but in reality it is reasonably close to the intended x value.

loltospoon
  • 239
  • 1
  • 9

4 Answers4

0

Your x value all seem to increase by 0.001. If that is the case, you could also calculate the index and return the y value at this index. This would be a lot more efficient.

func calculateIndex(forX x: Double) -> Int {
    let increase = 0.001
    return Int(x/0.001)
}

You can use the find method to find the index of the x value and then return the y value. I would multiply your values by 1000 and then compare the Int instead of comparing Double.

func findYValue(forX x: Double) -> Double? {
    let multiply = 1000
    let x = Int(multiply*x)
    if let index = array.index(where: { Int($0.0 * multiply) == x }) {
        return array[index].1 //found the y value
    }
    return nil //x is not in the array
}

Instead of using tuples, I would personally use CGPoint. The class has an x and a y property, which makes your code more readable.

Yannick
  • 3,210
  • 1
  • 21
  • 30
0

A good way of doing this is by declaring this function:

func getValueFromTuples(tupleArr:[(Double,Double)],n:Double)->Double?{
    for tuple in tupleArr{
        if tuple.0 == n{
            return tuple.1
        }
    }
    return nil
}

Then, you can use it like this:

var tupleArray: [(Double,Double)] = [(1.0, 12.0),(2.0,23.0),(3.0,34.0),(4.0,45.0),(5.0,56.0)]
var x:Double = 1.0
print(getValueFromTuples(tupleArr: tupleArray,n:x) ?? "No value found") // 12.0

Where the n argument is the value to be found, the tuple is the key-value pair formed by the numbers and getValueFromTuples returns the value y if x has been found, else nil.

This returns "No value found" if the value does not exist in the array of tuples.


Hope this helps!

Mr. Xcoder
  • 4,719
  • 5
  • 26
  • 44
0

I'd suggest to let your array to be an array of CGPoints. It's simply:

A structure that contains a point in a two-dimensional coordinate system.

However, if you want to get the y values based on searching the x:

let myArray = [
    (0.0, 500000.09999999998),
    (0.001, 18.332777589999999),
    (0.002, 18.332221480000001),
    (0.0030000000000000001, 18.331665000000001),
    (0.0040000000000000001, 18.331108140000001),
    (0.0050000000000000001, 18.33055092),
    (0.0060000000000000001, 18.32999332),
]

// this array should contains y values for a given x value
// for example, I search the x value of 0.0
let yValues = myArray.filter { $0.0 == 0.0 }.map { $0.1 }

print(yValues) // [500000.09999999998]

Hope this helped.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
0

Microsoft gives a very thorough explanation of how to compare 2 doubles. The basic premise is that you need to define a certain level of tolerance. The article the explores how to pick a good tolerance in most cases.

Here's code translated to Swift:

func areEqual(_ lhs: Double, _ rhs: Double, units: Int = 3) -> Bool {
    let lValue = Int64(bitPattern: lhs.bitPattern)
    let rValue = Int64(bitPattern: rhs.bitPattern)
    let delta = lValue - rValue

    return abs(delta) <= Int64(units)
}

Test:

var n = 0.0
for _ in 0..<10 {
    n += 0.1
}

// n should equal 1 but it does not
print(n == 1.0)          // false
print(areEqual(1.0, n))  // true

Back to your problem, it becomes straight forward after you defined how to test for equality in 2 doubless:

let x = 0.003
if let y = p.first(where: { areEqual($0.0, x) })?.1 {
    print(y)
}
Code Different
  • 90,614
  • 16
  • 144
  • 163