3

i have a file with the following content:

1005
1010
1011
1012
1013
1014
1009
1015
1006
77
1016
1017
1018
1019
1020
1021
1022
1023
1008

i want to read those lines into an array, sort them and write out chunks with 5 elements into a new file

the output file should looks like this (five elements each line.)

xyz 77,1005,1006,1008,1009
xyz 1010,1011,1012,1013,1014
...

my current batch script looks like this:

@echo off &setlocal disabledelayedexpansion

Sort Knot_unsort.dat>Knot_sort.dat

set /A i=0

for /F "delims=" %%a in (Knot_sort.dat) do (
    set /A i+=1
    call set array[%%i%%]=%%a
)
call set n=%%i%%

for /L %%i in (1,1,%n%) do (
    set /a b = %%i %% 5

    if %b% == 0 (
        :: does not work
    )

    call echo %%b%%
)

sorting the content and reading the lines into a array works. but after that i dont know how to concat five elements into a new variable and write them back into a new file. i tried to use modulo but the if statement is not working.

5
  • 2
    I can't believe that sorting works, because there is no code for that; I'd change the first loop to for /F "delims=" %%a in ('sort Knot_unsort.dat') do (, given the numbers always consist of 4 figures; in the second loop you must of course read array[%%i]; you could output the array elements by call < nul set /P _="%%array[%%i]%%" to avoid a trailing line-break, then prepend xyz and append , or a line-break conditionally, depending on the index %%i... Commented Oct 18, 2018 at 16:40
  • 2
    i used Sort Knot_unsort.dat>Knot_sort.dat Commented Oct 18, 2018 at 16:41
  • 1
    You don't need to assign all the values to an array. Once you have the file sorted you can just read the file in and count the lines and write out accordingly. Commented Oct 18, 2018 at 16:49
  • 1
    I have edited the question to include the OP's unspecified requirement to handle non 4-digit numbers. The numbers must be sorted numerically. Commented Oct 19, 2018 at 19:35
  • @JuKe - There are four (4) answers to your question. Can you select one of them as correct? This is part of why StackOverflow is helpful. Commented Oct 22, 2018 at 16:58

4 Answers 4

2

Another simpler approach, that don't store the lines in variables...

EDIT: Small bug fixed

@echo off
setlocal EnableDelayedExpansion

set "i=0"
<nul (for /F %%a in ('sort Knot_unsort.dat') do (
   set /A "i=(i+1)%%5"
   if !i! equ 1 (set /P "=xyz %%a") else set /P "=,%%a"
   if !i! equ 0 echo/
))
if %i% neq 0 echo/

Output:

xyz 1005,1006,1007,1008,1009
xyz 1010,1011,1012,1013,1014
xyz 1015,1016,1017,1018,1019
xyz 1020,1021,1022,1023

EDIT: New method to manage numbers with variable number of digits, up to 8

@echo off
setlocal EnableDelayedExpansion

set "i=0"
<NUL (
   for /F "tokens=2 delims=/ " %%a in (
      '(for /F %%i in (Knot_unsort.dat^) do @(set /A 100000000+%%i ^& echo /%%i^)^) ^| sort'
                                      ) do (
      set /A "i=(i+1)%%5"
      if !i! equ 1 (set /P "=xyz %%a") else set /P "=,%%a"
      if !i! equ 0 echo/
   )
)
if %i% neq 0 echo/
Sign up to request clarification or add additional context in comments.

4 Comments

What does set /P "=%%a " accomplish? What variable is set? Also, the OP sample output has a COMMA character between the numbers.
@lit: Ops, you are right! Comma added... If there is no variable at left of equal sign, no variable is set. This is useful to show the "prompt" with no LF at end...
@Aacini, I stole your code twice. See my updated answer
Oh man. I was trying to figure that out all day today when I had time. I see now that the parentheses needed to be escaped for it to work.
2

I normally don't format my code like this but @lit put me up to it.

@echo off & setlocal enabledelayedexpansion
((FOR /F "TOKENS=1* DELIMS=:" %%G IN ('sort Knot_unsort.dat^|findstr /N "^"') DO (set /A "mod=%%G %% 5" &IF !mod! == 0 (echo xyz!line! %%H& set "line=") ELSE (SET "LINE=!LINE! %%H"))) &IF DEFINED LINE echo xyz!line!)>foo.dat

In the real world I would format it like this.

@echo off & setlocal enabledelayedexpansion
((FOR /F "TOKENS=1* DELIMS=:" %%G IN ('sort Knot_unsort.dat^|findstr /N "^"') DO (
    set /A "mod=%%G %% 5" 
    IF !mod! == 0 (echo xyz!line! %%H& set "line=") ELSE (SET "LINE=!LINE! %%H")
)) &IF DEFINED LINE echo xyz!line!)>foo.dat

If you really want to do your array voodoo, you could simplify it to this.

@echo off & setlocal enabledelayedexpansion

for /F "tokens=1* delims=:" %%G in ('sort Knot_unsort.dat^|findstr /N "^"') do (
    set "array[%%G]=%%H"&set "n=%%G"
)

((for /L %%I in (1,1,%n%) do (
    set /a "mod= %%I %% 5"
    IF !mod! == 0 (echo xyz!line! !array[%%I]!&set "line=") ELSE (SET "LINE=!LINE! !array[%%I]!")
))&IF DEFINED LINE echo xyz!line!)>foo.dat

UPDATE: Well they say Imitation is the sincerest form of flattery. I have literally stolen code from @Aacini twice for this updated code. Here and Here

The Windows SORT command does not sort numerically. So you need to do some Tom Foolery to get it to do that. Here is my updated code.

@echo off
setlocal EnableDelayedExpansion

for /F "delims=" %%j in (Knot_unsort.dat) do (
   set j=0000000%%j
   set name[!j:~-8!]=%%j
)

set "i=0"
<nul (for /F "tokens=2 delims==" %%a in ('set name[') do (
   set /A "i=(i+1)%%5"
   if !i! equ 1 (set /P "=xyz %%a") else set /P "=,%%a"
   if !i! equ 0 echo/
))
if %i% neq 0 echo/

4 Comments

+1 That's a lot for only two (2) lines. Of course, neither this nor my one-liner would be a professional product as they are an understandability and maintenance mess.
@Squashman sort knot_unsort.dat does not sorting corrent if the input is a list with numbers like that: 1001;5;2991;3 it will put 3 and 5 at the end. do you have a solution that will sort like this: 3,5,1001,2991 ?
@Juke, I have added an additional code snippet to my answer.
"Imitation is the sincerest form of flattery" :) :)
2

This is relatively straightforward to do. This code get the file content, sorts it, then outputs it in groups of five (5).

powershell -NoProfile -Command ^
    "$items = Get-Content -Path '.\Knot_unsort.txt' | Sort-Object { [int]$_ };" ^
    "for ($i=0; $i -lt $items.Length; $i+=5) { 'xyz ' + $($items[$i..($i+4)] -join ',') }"

Sample output:

xyz 77 1005 1006 1007 1008
xyz 1009 1010 1012 1013 1014
xyz 1015 1016 1017 1018 1019
xyz 1020 1021 1022 1023

I am not much of a code golfer, but if you need a one-liner:

powershell -nop "$items=gc .\Knot_unsort.txt|sort{[int]$_};for($i=0;$i-lt$items.Length;$i+=5){'xyz '+$($items[$i..($i+4)]-join',')}

2 Comments

thanks @lit, just a hint, if the input file just contains numbers like 1001,5,2991,3 you have to convert the input into integer by using | Sort-Object { [int]$_ } to get the correct order
@JuKe - I do not recall that was part of the original question. I have changed this answer.
1

i now came up with this code. maybe somebody can use it. if you have a better and easy way i feel free to comment.

@echo off & setlocal enabledelayedexpansion

Sort Knot_unsort.dat>Knot_sort.dat

set /A i=0

for /F "delims=" %%a in (Knot_sort.dat) do (
    set /A i+=1
    call set array[%%i%%]=%%a
)
call set n=%%i%%

set var=
set newlist=
set /A j=0
for /L %%i in (1,1,%n%) do (
    set /a b = %%i %% 5

    if !b!==0 (
        set /A j+=1
        ::call echo %%b%%
        call set var=%%var%%%%array[%%i]%%,
        call set newlist[%%j%%]=%%var%%
        call set var=
    ) else (
        call set var=%%var%%%%array[%%i]%%,
    )

)
::call echo %j%

call set n=%%j%%

for /L %%i in (1,1,%n%) do (
    call echo XYZ - %%newlist[%%i]:~0,-1%%
) >> foo.dat

5 Comments

Nice array manipulation. I just would not want to use 36 lines of code when 3 lines of code can do it.
@lit, the code can be greatly reduced using a batch-file. Just gotta know what to do.
@Squashman - I agree that a .bat script could be much smaller than 36 lines. But, 3 lines of .bat sounds tough. Show me.
@lit, you know I am going to cheat. LOL
@Squashman - Please do. Lots of learning happens that way. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.