I can imagine some different scenarios, so I will try to address most of them.
1- You want to find only one number:
1.1 - Finding the actual number:
You can use min(by:)
:
let x = [1.2, 4.0, 3.4, 6.7, 8.9]
let target = 3.7
let closestValue = x.min { abs($0 - target) < abs($1 - target) }
print(closestValue) // prints Optional(4.0)
This approach is the most straightforward. You will get the result that returns the minimum value of the subtraction between the array element and the target.
1.2 - Finding the index:
You can also use min(by:)
, but first, you get the enumerated version of the array to get the indices.
let x = [1.2, 4.0, 3.4, 6.7, 8.9]
let target = 3.7
let closestIdx = x.enumerated().min { abs($0.1 - target) < abs($1.1 - target) }!.0
print(closestIdx) // prints 1
Note: Even though 3.4 is equally distant to 3.7 as 4.0, this approach will always return 4.0 as the answer because of floating-point arithmetic (you can check this blog post if you're interested in this topic).
2- You want to find all the closest numbers:
Since you've mentioned that there can be multiple numbers, I think this would be the method of your choice.
2.1 - Finding all closest numbers:
let x = [1.2, 3.4, 4.0, 6.7, 8.9]
let target = 3.7
let minDiff = x.map { return abs($0 - target) }.min()!
let closestValues = x.filter { isDoubleEqual(a: $0, b: target - minDiff) || isDoubleEqual(a: $0, b: target + minDiff) }
print(closestValues) // prints [3.4, 4.0]
The difference here is that we use filter()
to find all the values that are equally distant to a target. There may be repeated values, which can be eliminated using a Set if you wish.
2.2 - Finding the indices of all closest numbers:
The same idea of using enumerated()
again to take the indices.
let x = [1.2, 3.4, 4.0, 6.7, 8.9]
let target = 3.7
let minDiff = x.map { return abs($0 - target) }.min()!
let tuples = x.enumerated().filter { isDoubleEqual(a: $0.1, b: target - minDiff) || isDoubleEqual(a: $0.1, b: target + minDiff) }
let closestIndices = tuples.map { return $0.0 }
print(closestIndices) // prints [1, 2]
Note: isDoubleEqual(a: Double, b: Double) -> Bool
is a function that returns true
if the values a
and b
are considered equal according to floating-point arithmetic. See this post for more information - but note that you should adjust the epsilon to a value that you find suitable.
The complexity of these solutions is O(n).
A final note: if you have an array that is already sorted, as mentioned by other answers, you can take advantage of this property to find what you want using a binary search.