JuKe
JuKe

Reputation: 673

read file into array and write chunks out

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.

Upvotes: 3

Views: 144

Answers (4)

lit
lit

Reputation: 16236

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',')}

Upvotes: 2

Aacini
Aacini

Reputation: 67216

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/

Upvotes: 2

Squashman
Squashman

Reputation: 14290

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/

Upvotes: 2

JuKe
JuKe

Reputation: 673

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

Upvotes: 1

Related Questions