Increase amount of numbers for picking randomly - for-loop

There is a batch file that looks for Pen=n in the list.txt and changes its value (n) randomly from the given row of ten numbers (set "var[pen]=1 2 3 4 5 6 7 8 9 10"). But if there are more than ten numbers say twenty (set "var[pen]=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20") or hundred, it is still picking a number from first ten ones ignoring the rest.
#echo off
setlocal EnableDelayedExpansion
set "file=D:\list.txt"
set "temp=D:\temp.txt"
set "var[pen]=1 2 3 4 5 6 7 8 9 10" &
for /L %%i in (1,10,1%time:~-2%) do set "rand=!random!"
(for /F "usebackq tokens=1,2 delims==" %%a in ("%file%") do (
if defined var[%%a] (
call :getRandomValue var="!var[%%a]!"
echo %%a=!var!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > "%temp%"
move /Y "%temp%" "%file%"
pause > nul && pause > nul
goto :EOF
:getRandomValue value="list"
set /A "rand=!random:~-1!+1"
for /F "tokens=%rand%" %%v in (%2) do set "%1=%%v"
Any help would be appreciated.
edit:
the list.txt contains a list of stuff like pen paper rubber etc. with the corresponding value next to it.
pen=5
pencil=43
paper=0
rubber=22
what the bat file does is just putting random number picking in up from the row of numbers provided. in the following case it would change the value of pen to a random number from 1 to 10. but if I add some extra numbers more than ten it will then just ignore them.

You forgot to specify the origin post of this problem. In such a post, there is not any specification about how the probabilities must be given, but all the 3 examples provided have 10 probable values, so I assumed that all probabilities have 10 values. The fix is add the number of probabilities each value can have:
#echo off
setlocal EnableDelayedExpansion
rem Define the probabilities for new values
set "value[apple]=0 0 0 0 0 0 0 1 1 1" & set "num[apple]=10" & rem 0 (70%) or 1 (30%)
set "value[peach]=0 0 0 0 0 1 2 3 4 5" & set "num[peach]=10" & rem from 0 (50%) to 5 (the rest 50%)
set "value[banana]=54 68 82 96" & set "num[banana]=4" & rem each 25%
rem Randomize
for /L %%i in (1,10,1%time:~-2%) do set "ran=!random!"
(for /F "tokens=1,2 delims==" %%a in (input.ini) do (
if defined value[%%a] (
call :getRandomValue value=%%a
echo %%a=!value!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > output.ini
move /Y output.ini input.ini
goto :EOF
:getRandomValue value=item
set /A "ran=%random%%%num[%2]+1"
for /F "tokens=%ran%" %%v in ("!value[%2]!") do set "%1=%%v"
exit /B
You also forget (again) to provide the real format of the input file, that include [headers]:
[Berries]
Strawberry=1
Blackberry=-13
Blueberry=100
Cherry=6
[Fruits]
apple=0
peach=4
banana=18
orange=-2.5
[Vegetables]
Potato=44
Tomato=2
Onion=0
Garlic=17
EDIT 2022/01/08: New method added as requested in comment
As I already said, you have not specified the rules to define the probable values. I proposed a method that works correctly based on your first example, but then you define values that does not conform with my proposed method (10 possible values, like in your first example). I modified the method and then you invented values that does not conform either: "Why 100 values?" "Because any number above 31 will make the method fail..."
I modified the method (again) so you can define the probabilities via value:percent pairs. Here it is:
#echo off
setlocal EnableDelayedExpansion
rem Define the probabilities for new values as value:percent pairs
set "value[apple]=23:17 68:83" & rem 23 at 17%, 68 at 83%
set "value[peach]=0:50 1:10 2:10 3:10 4:10 5:10" & rem from 0 (50%) to 5 (the rest 50%)
set "value[banana]=54:25 68:25 82:25 96:25" & rem each 25%
rem Randomize
for /L %%i in (1,10,1%time:~-2%) do set "ran=!random!"
(for /F "tokens=1,2 delims==" %%a in (input.ini) do (
if defined value[%%a] (
call :getRandomValue %%a
echo %%a=!value!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > output.ini
move /Y output.ini input.ini
goto :EOF
:getRandomValue item
set /A "ran=%random%%%100+1, val=0"
for %%a in (!value[%1]!) do for /F "tokens=1,2 delims=:" %%x in ("%%a") do (
if %ran% gtr !val! set "value=%%x"
set /A val+=%%y
)
exit /B

What you are aiming to do is to randomly index from a list, which requires you to first determine the number of items in the list.
one method of doing so:
#Echo off
Set "var[pen]=a b c d e f g h i"
Rem enable enviroment for !expanison!
Setlocal EnableDelayedExpansion
Rem Build 'array', splitting string on spaces and incrementing array size count
Set _i=1& Set "item[1]=%var[pen]: =" & Set /A "_i+=1" & Set "item[!_i!]=%"
Rem index randomly from known array size [one indexed]
For /f delims^= %%i in ('Set /A !random! %%!_i! + 1')Do Echo(Item:%%i = !Item[%%i]!
Pause

Related

How do I generate a seven digit random number which is itself divisible by seven

I am working on a program, and all of the parts work perfectly except one, that part is supposed to generate a seven digit random number which is divisible by 7.
I am aware that there are similiar questions to mine, but I did not find my anwser within them, and despite trying I was myself only capable of somethimes generating such a number.
Any idea how to do so?
You can use the modulo function (see set /?):
#echo off
setlocal
set "number=%random%%random%%random%%random%%random%%random%%random%"
set "number=%number:~0,7%"
set /a remainder=number %% 7
if %remainder% equ 0 (
echo %number% is a multiple of 7
) else (
echo %number% divided by 7 gives a rest of %remainder%
)
Just in case, leading zero(s) is/are ok or even desired as a possibility:
#echo off
setlocal
set "number=%random%%random%%random%%random%%random%%random%%random%"
set "number=%number:~-7%"
set /a remainder=7%number% %% 7
if %remainder% equ 0 (
echo %number% is a multiple of 7
) else (
echo %number% divided by 7 gives a rest of %remainder%
)
Here's a slightly different method, which is designed to propagate a variable, named D7 with a seven digit value, which when divided by seven will return an exact integer:
This first example allows for leading 0's in the resulting value.
Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "D7="
For /L %%G In (0 1 9) Do For %%H In (
%Random:~-1%%Random:~-1%%Random:~-1%%Random:~-1%%Random:~-1%%Random:~-1%
) Do (Set /A D7 = 7%%H%%G %% 7
SetLocal EnableDelayedExpansion & If !D7! Equ 0 (EndLocal
Set "D7=%%H%%G"
GoTo :Next))
:Next
Set D7
Pause
Please note: It is possible that the resulting value could be 0000000 because leading 0's are allowed and 0 is divisible by every integer.
If you do not want to have leading 0's then a very small adaptation is needed:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "D7="
For /L %%G In (1 1 9) Do For %%H In (
%Random:~-1%%Random:~-1%%Random:~-1%%Random:~-1%%Random:~-1%%Random:~-1%
) Do (Set /A D7 = %%G%%H %% 7
SetLocal EnableDelayedExpansion & If !D7! Equ 0 (EndLocal
Set "D7=%%G%%H"
GoTo :Next))
:Next
Set D7
Pause

Using batch script I want to split a large file keeping the header same as master file [duplicate]

This question already has an answer here:
Split a CSV file into multiple files with header and given number of records
(1 answer)
Closed 1 year ago.
I have a text file. The first line is header. rest of the lines are data. It may contain thousand lines of data. I need to write a batch script which will split the master files into many files each of them contains maximum 500 lines of data and the same header as master file.
Master file
heder
1
2
3
4
.
.
.
.
1501
it will split the file into 4 files. The fourth one will have the header and 1501
You can get a total count of lines in a file using find and calculate the number of files needed by using a for /l loop on the count of the lines in steps of 500
the below approach examples such - in this way files are created with the header and lines output in accordance with the 500 per file using a paired GTR LEQ conditional test.
#Echo off & CD /D "%~dp0"
:# Primary environment has Delayed Expansion Disabled until after assignment of input
:# to retain '!' characters.
Setlocal EnableExtensions DisableDelayedExpansion
Set "line[i]="
Set "files="
:# Get a count of total lines and how many files to make per 500
for /f %%a in ('type "infile.txt"^|find "" /v /c') do Set /A TTL=%%a-1
For /l %%i in (0 500 %TTL%)Do Set /A files+=1
Set /P "Header=" <"infile.txt"
:# Delayed expansion provides protection against poison characters
Setlocal EnableDelayedExpansion
:# Create or Overide each outfile using the assigned input from set /p
For /l %%i in (1 1 %files%)Do >"Outfile%%i.txt" Echo(!Header!
Endlocal
:# Outer for /f loop skips header line; counts each line in.
:# Inner for /l loop iterates over group size with assigned offset 'Stop'
:# Dual GTR LEQ conditional test of Lne[i] used to output in desired group
For /f "Skip=1 Delims=" %%G in (infile.txt)Do (
Set /A "Line[i]+=1"
Set "Line=%%G"
Setlocal EnableDelayedExpansion
Set "file[i]=0"
For /l %%i in (0 500 !TTL!)Do (
Set /A "Stop=%%i+500"
Set /A "file[i]+=1"
If !Line[i]! GTR %%i If !Line[i]! LEQ !Stop! (
Title File: !file[i]! / !files! Line: !Line[i]! / !TTL!
>>"Outfile!file[i]!.txt" Echo(!Line!
)
)
Endlocal
)
Here you go:
#echo off
setlocal EnableDelayedExpansion
set /a maxNoOfLinesPerFile = 500
set /a lineCount = 0
set /a fileCount = 0
set header=""
set outFileNamePrefix=outFile
for /F "tokens=*" %%A in (source.txt) do (
if !lineCount!==0 (
set header=%%A
) else (
set /a n = !lineCount! %% !maxNoOfLinesPerFile!
REM echo !n!
if !n!==1 (
set /a fileCount = fileCount + 1
set outFileName=!outFileNamePrefix!_!fileCount!.txt
echo !outFileName!
echo !header! >> !outFileName!
echo %%A >> !outFileName!
) else (
echo %%A >> !outFileName!
)
)
set /a lineCount = lineCount + 1
)

Compare array of numbers in a batch script

I'm trying to compare a sequence of 9 numbers (separated by ,) using a batch file.
The comparison is always made by the corresponding sequence like:
mPrevious[0] <-> mCurrent[0]
mPrevious[1] <-> mCurrent[1]
I need to know if at least one sequece have changed. In the example bellow, 234 changed to 230 and 146 to 149.
The sketch I have so far is:
setlocal ENABLEDELAYEDEXPANSION
#echo off
set mPrevious=229,234,235,127,58,0,131,133,146
set mCurrent=229,230,235,127,58,0,131,133,149
for /f "tokens=1,2,3,4,5,6,7,8,9 delims=," %%a IN ('echo !mPrevious!') do (
)
The number of entries (currently 9) might change in the future. But for now they are just 9.
I'm not sure what is the proper way to do it inside a batch script.
#echo off
title <nul && title ...\%~nx0
setlocal enabledelayedexpansion
set "_mPrevious=229,234,235,127,58,0,131,133,146"
set "_mCurrents=229,230,235,127,58,0,131,133,149"
echo/!_mPrevious!|find "!_mCurrents!" >nul && (
endlocal & echo\Nothing changed^!! & goto :EOF )
for %%i in (!_mPrevious!)do set /a "_i+=1+0" && call set "_mPrev_!_i!=%%~i"
for %%j in (!_mCurrents!)do set /a "_j+=1+0" && call set "_mCurr_!_j!=%%~j"
if !_i! neq !_j! endlocal & echo\Varyables have different lengths^!! & goto :EOF
for /L %%L in (1 1 !_j!)do if !_mPrev_%%~L! neq !_mCurr_%%~L! echo\!_mPrev_%%~L! updated to: !_mCurr_%%~L!
endlocal && goto :EOF
Outputs:
234 updated to: 230
146 updated to: 149
One simple way to do this only if necessary and only if both variable has same length:
Make a first comparison if the variables are the same, there was a change in the values:
echo/!_mPrevious!|find "!_mCurrents!" >nul && (
endlocal & echo\Nothing changed^!! & goto :EOF )
And a second if they continue with the same length:
if !_i! neq !_j! endlocal & echo\Variables have different lengths^!! & goto :EOF
Obs.: 1. I prefer replace [ ] to one simple _
Obs.: 2. Also, change i+= to _i+=1+0, where no need predefined set command: set i=0
The FOR token delimiters are: <SPACE> <TAB> <NBSP> , ; =
Therefore, you can put it into a FOR loop, but it would fail if the content contained * or ?.
#echo off
====SETLOCAL EnableDelayedExpansion EnableExtensions
set/a"#=cnt=0"
::Define lists
set "mPrevious=229,234,235,127,58,0,131,133,146"
set "mCurrent=229,230,235,127,58,0,131,133,149"
FOR %%P in (!mPrevious!) do (
FOR %%C in (!mCurrent!) do (
if !cnt! equ !#! echo(%%P %%C
set/a"cnt+=1"
)
set/a"cnt=0,#+=1"
)
This is an approach using some self-expanding code:
#echo off
setlocal EnableDelayedExpansion
rem // Define constants here:
set "mPrevious=229,234,235,127,58,0,131,133,146"
set "mCurrents=229,230,235,127,58,0,131,133,149"
rem // Initialise auxiliary variables and indexes:
set "nPrevious=,%mPrevious%" & set /A "i=0"
set "nCurrents=,%mCurrents%" & set /A "j=0"
rem // Convert lists to arrays using self-expanding code:
set "_=%nPrevious:,=" & set /A "i+=1" & set "nPrevious[!i!]=%"
set "_=%nCurrents:,=" & set /A "j+=1" & set "nCurrents[!j!]=%"
rem // Verify availability of arrays:
> nul 2>&1 set nPrevious[ || set /A "i=0"
> nul 2>&1 set nCurrents[ || set /A "j=0"
rem // Determine minimal and maximal count:
if %j% gtr %i% (set /A "k=i, l=j" & set "_=#") else (set /A "k=j, l=i" & set "_=")
rem // Compare corresponding elements:
for /L %%K in (1,1,%k%) do if !nPrevious[%%K]! neq !nCurrents[%%K]! (
echo [%%K]: !nPrevious[%%K]! -^> !nCurrents[%%K]!
)
rem // Return removed or added elements:
set /A "k+=1" & for /L %%K in (!k!,1,%l%) do if defined _ (
echo [%%K]: --- -^> !nCurrents[%%K]!
) else (
echo [%%K]: !nPrevious[%%K]! -^> ---
)
endlocal
Sample output, relying on the data of the question:
[2]: 234 -> 230
[9]: 146 -> 149

Batch Programming (Nested loops) using labels, program does not work

I don't understand why this script doesn't seem to work and doesn't even pause to see where the error is.. Here is the code for the batch file:
I want this batch to output a series of birthdays starting from Ihf0101 till Ihf3112
set /a month=1
:m
if %month% leq 12
(
set /a day=1
:d
if %day% leq 31
(
if %day% leq 9 set birthday=Ihf0%day%
if %day% gtr 9 set birthday=Ihf%day%
if %month% leq 9
(
set birthday=%birthday%0%month%
echo %birthday%
)
if %month% gtr 9
(
set birthday=%birthday%%month%
echo %birthday%
)
set /a day+=1
goto :d
)
set /a month+=1
goto :m
)
pause
Use for /L loops instead:
#echo off
setlocal enabledelayedexpansion
set "y=2017"
for /l %%m in (101,1,112) do (
set "m=%%m"
for /l %%d in (101,1,131) do (
set "d=%%d"
xcopy /d:!m:~1!-!d:~1!-%y% /l . .. >nul 2>&1 && echo lhf!d:~1!!m:~1!
)
)
two little tricks:
- counting from 101 to 131 and taking the last two digits only gives you a two-digit format always (with leading zero for numbers below 10)
- using xcopy to check if the date is really existent (I learned that here) (necessary to know the year for proper calculation of leap-years)

Windows batch script random order of insert to text file

So I have a text file that I read which contains multiple lines of words. For now it contains "Successful" and failed.
Here's my code.
setlocal enabledelayedexpansion
for /l %%x in (1, 1, 50) do (
for /f "tokens=*" %%a in (D:\Errors.txt) do echo %%x %%a >>D:\list.txt
)
Basically what I want to output are the words in Errors.txt at random which is mapped from 1 - 50.
Currently this is the output of my code and it's not at random. Also the numbering repeats which I guess is expected due to the loop. Any help would greatly be appreciated. Thanks!
1 Successful
1 Failed
2 Successful
2 Failed
3 Successful
3 Failed
4 Successful
4 Failed
5 Successful
5 Failed
6 Successful
6 Failed
7 Successful
7 Failed
Basically end goal should be like this. Successful/Failed are applied at random while the numbers 1 - 50 are consistent.
1 Successful
2 Failed
3 Failed
4 Successful
5 Successful
6 Successful
7 Failed
This method works with any number of lines in the Errors.txt file:
#echo off
setlocal EnableDelayedExpansion
(
rem Load the lines from the file
set n=0
for /F "delims=" %%a in (D:\Errors.txt) do (
set "line[!n!]=%%a"
set /A n+=1
echo !n! %%a
)
rem Repeat same lines the rest of times in random order
set /A nP1=n+1
for /L %%i in (!nP1!,1,50) do (
set /A i=!random! %% n
call echo %%i %%line[!i!]%%
)
) > D:\list.txt
#echo off
setlocal EnableDelayedExpansion
set n=0
(
REM read from file
for /f "tokens=*" %%a in (D:\Errors.txt) do (
set /a n+=1
echo !n! %%a
)
REM for the rest until 50:
for /l %%a in (!n!,1,49) do (
set /a n+=1
set /a x=!random! %% 2
if !x!==0 (
echo !n! successful
) else (
echo !n! failed
)
)
)>D:\list.txt
type D:\list.txt

Resources