3

I have a batch script which collects data and inserts it into an array named output of size cnt declared as set "output[!cnt!]=%%a"

I have an iterator for loop for /L %%n in (1 3 !cnt!) DO echo !output[%%n]! which will echo the

1st, 4th , 7th , 10th element and so on...

How do I modify the function so as to echo the following sequence,

1st,2nd,4th,5th,7th,8th,10th,11th element and so on....

I am looking for something on the lines of DO echo !output[%%n]! !output[%%n+1]! but I am not getting the syntax right. Any other solution will also do.

This is how I would have done it in C programming

for(n=1;i<cnt;n+=3){printf("%d %d",output[n],output[n+1])}

Step-wise as follows :

Initially n=1 display output[1] output[2]

After one iteration n=4 display output[4] output[5]

After one more iteration n=7 display output[7] output[8]

My ulterior motive is to obtain a generalized syntax, where we can display the (n+m)th element for(n=1;n<cnt;n+=3){printf("%d %d",output[n],output[n+m])}

The solution need not contain a for loop , do while will also work.

Community
  • 1
  • 1
DannyBoi
  • 636
  • 1
  • 7
  • 23
  • Change the step 4 to 1 in this loop `for loop for /L %%n in (1 4 !cnt!) DO echo !output[%%n]!` ==> `for loop for /L %%n in (1 1 !cnt!) DO echo !output[%%n]!` – Hackoo Jul 31 '16 at 07:33
  • @Hackoo That wont work, it will echo every value. – DavidPostill Jul 31 '16 at 10:08
  • 1
    You may read [this description](http://stackoverflow.com/questions/10166386/arrays-linked-lists-and-other-data-structures-in-cmd-exe-batch-script/10167990#10167990): "To get the value of an element when the index changes inside FOR/IF, enclose the element in double percent symbols and precede the command with `call`. Another way to achieve the previous process is to use an additional FOR command to change the delayed expansion of the index by an equivalent replaceable parameter, and then use the delayed expansion for the array element". – Aacini Jul 31 '16 at 13:38

2 Answers2

4

How do I modify the function so as to echo in the following sequence,

1st,2nd,4th,5th,7th,8th,10th,11th element and so on....

What you are trying to do is print every element that is not a multiple of 3. The easiest way to do this is with a modulo operation.

Psuedocode:

if %%n modulo 3 >= 1 then print something.

The modulus operator in batch file arithmetic using set /a is %%.

Example batch file (test.cmd):

@echo off
setlocal enabledelayedexpansion
for /l %%n in (1 1 20) do (
rem print values where cnt is not a multiple of 3
  set /a _mod=%%n %% 3
  if [!_mod!] GEQ [1] (
    echo %%n
    )
  )
endlocal

Output:

F:\test>test
1
2
4
5
7
8
10
11
13
14
16
17
19
20

You can use the same technique in your batch file.

Snippet:

@echo off
setlocal enabledelayedexpansion
rem collect data and insert into array
rem ...
rem print values where cnt is not a multiple of 3
for /l %%n in (1 1 !cnt!) do (
  set /a _mod=%%n %% 3
  if [!_mod!] GEQ [1] (
    echo !output[%%n]!
    )
  )
endlocal

More general solution

This is how I would have done it in C programming

for(n=1;i<cnt;n+=3){printf("%d %d",output[n],output[n+1])}

Example batch file (test.cmd):

@echo off
setlocal enabledelayedexpansion
for /l %%n in (%1 3 20) do (
    set /a _next=%%n+1
    echo %%n !_next!
    )
  )
endlocal

Notes:

  • Pass the starting value as an argument to the batch file.
  • Modify as necessary to output your array values.

Usage:

F:\test>test 1
1 2
4 5
7 8
10 11
13 14
16 17
19 20

F:\test>test 2
2 3
5 6
8 9
11 12
14 15
17 18
20 21

An even more general solution

But I said in the comments I want to output 2,3,6,7,10,11,14,15,18...

Note that your c solution will not handle this case, even if you change the loop starting value ...

You need to have two variable parameters to the for loop, one for the start value, and one for the increment.

Example batch file (test.cmd):

@echo off
setlocal enabledelayedexpansion
for /l %%n in (%1 %2 20) do (
    set /a _next=%%n+1
    echo %%n !_next!
    )
  )
endlocal

Usage:

F:\test>test 2 4
2 3
6 7
10 11
14 15
18 19

Further Reading

  • An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
  • for /l - Conditionally perform a command for a range of numbers.
  • if - Conditionally perform a command.
  • set - Display, set, or remove CMD environment variables. Changes made with SET will remain only for the duration of the current CMD session.
DavidPostill
  • 7,734
  • 9
  • 41
  • 60
  • That does the trick, in this case, however I am looking for a more generalized solution. Imagine that the loop had to start from the 2nd element then the desired sequence would be `2,3,6,7,10,11,14,15,18and so on....`Let me make the question more clear. – DannyBoi Jul 31 '16 at 11:15
  • @DanielFurtado You can't generalise in that way. Now you are printing 2, skipping 2, etc ... that's a different problem. – DavidPostill Jul 31 '16 at 11:24
  • @DanielFurtado In addition, please don't change your very specific requirements when you have an answer. That invalidates my answer, which is not a nice thing to do when I've spent my (free) time solving your original question. If you have **new** requirements ask a **new** question (and accept this answer which solves your question as it stands). – DavidPostill Jul 31 '16 at 11:26
  • that is the exact reason , I had not mentioned the sequence in my original question in the title. I had left as **indexing the (n+1)th element** No doubt I am extremely thankful for your effort, it doesn't completely satisfy what I am looking for. – DannyBoi Jul 31 '16 at 11:38
  • @DanielFurtado Then next time don't put explicit requirements in the body of your question. I have modified my answer to address your more general case. – DavidPostill Jul 31 '16 at 11:54
  • @DanielFurtado Note that your `c` solution will not output `2,3,6,7,10,11,14,15,18...` even if you change the loop start value. – DavidPostill Jul 31 '16 at 11:58
  • 3
    @DavidPostill Your generalized solution works fine to compute the indexes, but I suppose the problem of the OP is to get the array content from such an index, as this isn't obvious in batch – jeb Jul 31 '16 at 12:23
4

I would use a loop with increment of three.

@echo off
setlocal EnableDelayedExpansion

REM Building a test array
for /L %%n in (1 1 12) do set "arr[%%n]=_%%n_"

for /L %%n in (1 3 12) do (
    set /a idxAddOne=%%n+1
    for %%m in (!idxAddOne!) do echo !arr[%%n]! !arr[%%m]!
)

The main problem is the expansion inside code blocks.
Calculating the idx+1 can be done with set /a idxAddOne=%%n+1, but using the new index is a bit tricky, as you want the content of the array.
I use here an extra for loop to copy the index into a new parameter variable %%m.
It could be also solved with double expansion by CALL.

call echo !arr[%%n]! %%arr[!idxAddOne!]%%
jeb
  • 78,592
  • 17
  • 171
  • 225
  • @DanielFurtado You said in the comment to my answer "Imagine that the loop had to start from the 2nd element then the desired sequence would be 2,3,6,7,10,11,14,15,18and so on....". This answer doesn't address that, mine does ... – DavidPostill Jul 31 '16 at 12:05
  • @DanielFurtado I really don't understand where you are coming from. You discounted my answer because " however I am looking for a more generalized solution. " and then you accept an answer that is not generalised :/ – DavidPostill Jul 31 '16 at 12:12
  • @DavidPostill ...at this point the "More generalised" section of your answer also has what I am looking for. If I could, I definitely would accept your solution too but that option is not there. – DannyBoi Jul 31 '16 at 12:25