Fast way to test if a value is between several ranges

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Aacini
Expert
Posts: 1913
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Fast way to test if a value is between several ranges

#1 Post by Aacini » 03 Jul 2012 13:08

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

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

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

#2 Post by jeb » 03 Jul 2012 13:22

+1 :D

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

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

#3 Post by Squashman » 03 Jul 2012 14:07

+∞ :mrgreen:

Aacini
Expert
Posts: 1913
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

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

#4 Post by Aacini » 03 Jul 2012 16:24

Tnxs, you both :P :)

Could we be more descriptive, perhaps :?:

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

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

#5 Post by foxidrive » 03 Jul 2012 22:53

plus 1 :lol:

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

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

#6 Post by Ed Dyreen » 04 Jul 2012 00:57

'
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: :!:

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

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

#7 Post by einstein1969 » 04 Jul 2012 15:51

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
Last edited by einstein1969 on 05 Jul 2012 08:11, edited 3 times in total.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

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

#8 Post by foxidrive » 04 Jul 2012 20:19

Edited
Last edited by foxidrive on 05 Jul 2012 08:31, edited 1 time in total.

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

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

#9 Post by einstein1969 » 05 Jul 2012 08:17

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

Post Reply