Hi all
Im looking for a function similar to lookup but in ahk. I would like to provide a value, say: 3.72 and then have the script lookup in a range i provide for example
3.65
3.7
3.75
and return the closest value. In this case, 3.7
I don't want to use an external file to contain the lookup range if possible, i would like to have it in the script. Anyone know how i would go about this?
Match Closest Value
-
- Posts: 1472
- Joined: 05 May 2018, 12:23
Re: Match Closest Value
Many thanks for that. Do you know if there is a way to achieve this without using loops as speed is key for me.
Something like
Giving the result 1? Also i need to be able to specify the result values, i cant just round up or down to the nearest whole number because sometimes i will face scenarios like this
I basically have an array with 350 numbers in, and i need to provide a value and find the closest match in that array of 350
Something like
Code: Select all
array := [1, 2, 3, 4]
MsgBox, "match 1.2"(array*)
Code: Select all
array := [1.71, 1.72, 1.73, 1.74]
MsgBox, "match 1.7312"(array*)
Re: Match Closest Value
You're going to need loops, whether or not the thread linked provided the most efficient solution or not I don't know. But you surely need to loop through the entire array, you can't just magically find the closest one without checking them all.jc0r wrote: ↑17 Nov 2019, 06:03Many thanks for that. Do you know if there is a way to achieve this without using loops as speed is key for me.
Something like
Giving the result 1? Also i need to be able to specify the result values, i cant just round up or down to the nearest whole number because sometimes i will face scenarios like thisCode: Select all
array := [1, 2, 3, 4] MsgBox, "match 1.2"(array*)
I basically have an array with 350 numbers in, and i need to provide a value and find the closest match in that array of 350Code: Select all
array := [1.71, 1.72, 1.73, 1.74] MsgBox, "match 1.7312"(array*)
Re: Match Closest Value
Hi there. I checked out the linked threads and found the solutions there unsatisfactory. They're not encapsulated in functions so they're not even portable without legwork
Here is what I came up with:
Here is what I came up with:
Code: Select all
fn_findClosestNumber(param_number,param_array) {
canidateArray := []
for Key, Value in param_array {
element := {}
element.param_number := Value
element.difference := abs(param_number - Value)
if (canidateArray[canidateArray.Count()].difference > element.difference || canidateArray.Count() == 0) {
canidateArray.push(element)
}
}
return canidateArray[canidateArray.Count()].param_number
}
Code: Select all
msgbox, % fn_findClosestNumber(1.5, [3,4,1.8,0.2])
; => 1.8
msgbox, % fn_findClosestNumber(1.5, [1.4,0.2,2])
; => 1.4
Re: Match Closest Value
One thing I find useful for this sort of 'is a value within a range' task, is to use an intermediate array.
You round the needle value down, and look up the rounded value in the intermediate array.
By using the rounded value, you can jump to a relevant place in the list.
Here's some code:
Some of it is a little fiddly, so do notify of any issues.
Cheers.
You round the needle value down, and look up the rounded value in the intermediate array.
By using the rounded value, you can jump to a relevant place in the list.
Code: Select all
array:
1 1.23
2 1.41
3 1.59
4 2.21
5 2.47
6 2.67
7 4.15
8 4.58
9 4.96
10 5.18
intermediate array:
1 1 [1.23]
2 4 [2.21]
4 7 [4.15]
5 10 [5.18]
e.g. key/value '5 10', the smallest value in the list where
the integer part is 5, is the 10th item in the list
Some of it is a little fiddly, so do notify of any issues.
Code: Select all
;==================================================
w:: ;generate random numbers
vOutput := ""
Loop 20
{
;vNum := Random(0.0, 10.0)
Random, vNum, 0.0, 10.0
vOutput .= Format("{:0.2f}", vNum) "`r`n"
}
Sort, vOutput, % "D, N"
Clipboard := vOutput
MsgBox, % "done"
return
;==================================================
q:: ;find nearest values
vList := "1.23,1.41,1.59,2.21,2.47,2.67,4.15,4.58,4.96,5.18,6.17,6.30,6.99,7.81,8.00,8.33,8.68,8.72,8.77,9.48"
oArray := StrSplit(vList, ",")
;generate intermediate table:
oMap := Object()
vNumLast := ""
Loop Parse, vList, % ","
{
vNum := Floor(A_LoopField)
if !(vNum = vNumLast)
oMap[vNum] := A_Index
vNumLast := vNum
}
;list intermediate table:
;e.g. key/value '5 10', the smallest value in the list where
;the integer part is 5, is the 10th item in the list
vOutput := ""
for vKey, vValue in oMap
vOutput .= vKey " " vValue " " oArray[vValue] "`r`n"
MsgBox, % "lookup table:`r`n" "k v a[v]`r`n" vOutput "`r`n"
;find closest match:
vOutput := ""
Loop 21
{
vNum := (A_Index-1)*0.5
vNum2 := Floor(vNum)
Loop
{
if (vNum2 < 0)
{
vIndex := 1
break
}
if oMap.HasKey(vNum2)
{
vIndex := oMap[vNum2]
break
}
vNum2--
}
if !(vIndex = 1)
vIndex--
vDiff := Abs(vNum-oArray[vIndex]), vIndex2 := vIndex
Loop
{
vIndex++
if !oArray.HasKey(vIndex)
break
vDiff2 := Abs(vNum-oArray[vIndex])
if (vDiff2 >= vDiff)
break
vDiff := vDiff2, vIndex2 := vIndex
}
vOutput .= vNum " " oArray[vIndex2] "`r`n"
}
MsgBox, % "number and closest match:`r`n" vOutput
return
;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA