Finding the X closest values to Y in an array?

Hello DevForum! Hopefully you all are having a good day.

In a table that is has unsorted number values, how would I find the X closest values to the number Y? An example case would be something like…

{5,1,3,2,4}, Results : 3, Start at Number : 4 
-- {5,3,4}, The initial starting number can be found in the solution

The resulting array doesn’t need to be sorted. I’m looking at binary searching but the initial array would need to be sorted.

Anything helps, thanks!

Loop through the array until you find the LEAST difference from the number.

local numbers = {1,3,9,0,4}
local goal = 5 --4 is closest to 5, now let's figure it out
local closest
local lastDifference = 99999999--Start very high so any number can beat it at first
for i,v in pairs(numbers) do
    --Loop through array
    local distance = math.abs(goal-v) --Distance away
    if distance<lastDifference then
        closest = v --Note, i is the location in the array, v is the value
        lastDifference = distance
    end
end
print(closest)
3 Likes

Thanks for the quick reply! I was looking for something that would return multiple values though.
In your example, if I were to get the 3 closest values, the desired result would be…

{1,3,4} or {3,4,9} (depending on if the code touched the 9 or the 1 first)

I would calculate for each index the difference to the desired value. Then, sort the table so the indexes with the smallest differences are at the start and then fetch the desired number of values. Here’s an example:

local Values = {1, 34, 8, 5, 3, 13, 21, 2}

local closestTo = 9 -- number you want to be close to
local fetchCount = 3 -- how many numbers to return

-- replace number with a pair of the number and the difference to the desired number
for i = 1, #Values do
	Values[i] = {Values[i], math.abs(closestTo - Values[i])}
end

-- sort the table of Values so that the indexes at the start have the smallest differences
table.sort(
	Values,
	function(a, b)
		return a[2] < b[2]
	end
)

-- print the first 'fetchCount' numbers
for i = 1, fetchCount do
	print(Values[i][1])
end

This does edit the original table though by replacing the numbers by ‘pairs’ (tables with two indexes). You could alternatively first copy the table if you do not want to alter the original.

11 Likes

Thank you! I tested it out and it worked for me!
Thanks for also helping, @REALTimothy0812 :slight_smile:

As Zomebody mentioned, you can do this without changing the structure of the original table. This version only changes its order.

local function getClosestValues(values, closestTo, fetchCount)
    table.sort(values, function(a, b)
        return math.abs(closestTo - a) < math.abs(closestTo - b)
    end)
    return unpack(values, 1, fetchCount) -- enclose this in {} if you want it as a table
end
7 Likes