Page 1 of 1

Fast way to test if a value is between several ranges

Posted: 03 Jul 2012 13:08
by Aacini
The usual way to check if a given variable contain anyone of several possible values is by trying to delete the variable from the list of values; if the result is the same, the variable is not in the list:

Code: Select all

set values=10,25,45,90,120,180
if "!values:%variable%=!" neq "!values!" echo The variable IS in the list
However, if the possible values may include a range, the test can not be achieved directly:

Code: Select all

set values=10,25-35,45,90-110,120-150,180
The usual way to achieve this test is via a FOR loop that get each value or range from the list and perform individual tests, but this method is slow.

The fastest way to do this test is by defining an array with individual elements for each one of the possible values, including one element for each value in a range, so the testing is immediate:

Code: Select all

if defined testValue[%variable%] echo The variable IS in the list
However, if the number of testing values is large...

Code: Select all

set values=10-1500,2000-25000, 32000
... this method requires a large amount of environment space in the testing variables, but what is worst is that the time involved just in creating the array may be much larger than the FOR iterative method's.

There is another approach to solve this problem using an aritmethic expression. For example, we may check if a variable is 10 or 45 with this command:

Code: Select all

set /A test=(10-variable)*(45-variable)
If the variable have anyone of these two values the test is zero. To check if the variable is into a range, we may use this method:

Code: Select all

set /A (lowerLimit-variable)                          is negative or zero if variable >= lowerLimit
set /A (variable-UpperLimit)                          is negative or zero if variable <= upperLimit, so
set /A (lowLimit-var)*(var-UpLimit)                   is positive or zero if variable is in range,
                                                         negative otherwise, and
set /A aux=(Low-var)*(var-Up), test=(aux-1)/aux       set test=0 if variable is in range,
                                                          test=1 otherwise
Previous expression requires a small provision in case the variable is equal to anyone of the limits (to manage the division by zero). This way, to test a variable vs. several individual values or ranges, just assemble the appropiate aritmethic expression combining all intermediate values with multiplications. If the final result is zero, the variable is equal to one of the individual values or is into one range.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set /P "values=Enter the list of values or ranges: "
call :makeTestingExpr values
:next
   set n=
   set /P "n=Enter a number to test: "
   if not defined n goto :EOF
   set /A r=%expr% 2> NUL
   if %r% equ 0 echo Number IS in values
goto next


:makeTestingExpr valuesVar
rem Assemble the testing expression for the variable given in %1
set expr=1
for %%b in (!%1!) do (
   for /F "tokens=1,2 delims=-" %%c in ("%%b") do (
      if "%%d" equ "" (
         rem Individual value: multiply previous expr by direct subtract
         set "expr=!expr!*(%%c-n^)"
      ) else (
         rem Range value pair: use range expression at this point, then continue
         set "expr=!expr!,a=r,r=0,b=(%%c-n^)*(n-%%d),r=(b-1)/b*a"
      )
   )
)
exit /B


Antonio

Re: Fast way to test if a value is between several ranges

Posted: 03 Jul 2012 13:22
by jeb
+1 :D

Re: Fast way to test if a value is between several ranges

Posted: 03 Jul 2012 14:07
by Squashman
+∞ :mrgreen:

Re: Fast way to test if a value is between several ranges

Posted: 03 Jul 2012 16:24
by Aacini
Tnxs, you both :P :)

Could we be more descriptive, perhaps :?:

Re: Fast way to test if a value is between several ranges

Posted: 03 Jul 2012 22:53
by foxidrive
plus 1 :lol:

Re: Fast way to test if a value is between several ranges

Posted: 04 Jul 2012 00:57
by Ed Dyreen
'
Aacini wrote:Could we be more descriptive, perhaps :?:
Your current code has a limitation, negative scopes are causing problems

Code: Select all

Enter the list of values or ranges: -10-10
Enter a number to test: 0
Enter a number to test:
This is partially due to the fact you chose the '-' for ranges but it also precedes any negative number.

Code: Select all

@echo off &setlocal enableDelayedExpansion

set /P "values=Enter the list of values or ranges: "
call :makeTestingExpr values
for /l %%ç in () do set "n=" &set /p "n=Enter a number to test: " &if defined n (

       2>nul set /a r = !expr!
rem    echo.expr=!expr!_ &echo.a=!a!_ &echo.b=!b!_
       if !r! == 0 echo.Number IS in values

) else exit

:makeTestingExpr ( valuesVar )
::
:: Assemble the testing expression for the variable given in %1
::
:: (
       set /a expr = 1 &for %%? in (

              !%~1!

       ) do   for /f "tokens=1,2 delims=~" %%a in (

              "%%~?"

       ) do   if "%%~b" equ "" (

              rem Individual value: multiply previous expr by direct subtract
              set "expr=!expr!*(%%~a-n)"

       ) else (

              rem Range value pair: use range expression at this point, then continue
              set "expr=!expr!,a=r,r=0,b=(%%~a-n)*(n-%%~b),r=(b-1)/b*a"
       )
:: )
exit /b 0

Code: Select all

Enter the list of values or ranges: -10~10,100~1000,10000
Enter a number to test: -11
Enter a number to test: -10
Number IS in values
Enter a number to test: 0
Number IS in values
Enter a number to test: 10
Number IS in values
Enter a number to test: 11
Enter a number to test: 500
Number IS in values
Enter a number to test: 1001
Enter a number to test: 10000
Number IS in values
Enter a number to test:
Impressive :wink: :!:

Re: Fast way to test if a value is between several ranges

Posted: 04 Jul 2012 15:51
by einstein1969
Thanks to all!

I'll use this for my mini-monitor system for getup allarm if value in range!!!

This is my first attemp. http://www.dostips.com/forum/viewtopic.php?f=3&t=3502

EDIT: Open topic apart

Re: Fast way to test if a value is between several ranges

Posted: 04 Jul 2012 20:19
by foxidrive
Edited

Re: Fast way to test if a value is between several ranges

Posted: 05 Jul 2012 08:17
by einstein1969
should be a problem of language. I added a topic with a new version that drives the choice of the counter. You can try with a counter \ processor. Look previus post