Search code examples
batch-filearraylistcmdlogicdelayedvariableexpansion

Batch array, associative array, and how to navigate in array


How can I call in batch a multiple level of array ?

I want to create an array of unique value with multiples data, then I will manage to make an associative array after unyfing the values.

I have a csv file with lot of value like this :

R14201;03h22mn55s;profile;15;
R14201;03h23mn02s;profile,15;
R14201;03h23mn07s;home;15;
R14202;03h23mn12s;profile;12;
R14201;03h23mn16s;home;14;
R14203;03h23mn19s;profile;15;
R14203;03h23mn22s;profile;11;
R14201;03h23mn25s;profile;15;
R14204;03h23mn31s;profile;12;
...

What I want to do :

1 - Get unique reference of RXXX (success)

2 - See changes in third columns, only changes and their order

3 - See different values of last column

So at the end, the desire state will be :

R14201 : [profile, home, profile], [15, 14]
R14202 : [profile], [12]
R14203 : [profile], [15, 11]
R14204 : [profile], [12]

In terme of variable, I will have something like that :

myArray[R14201].NAME=R14201
myArray[R14201].PROFILE[0]=profile
myArray[R14201].PROFILE[1]=home
myArray[R14201].PROFILE[2]=profile
myArray[R14201].NUMBER[0]=15
myArray[R14201].NUMBER[1]=14


myArray[R14202].NAME=R14202
myArray[R14202].PROFILE[0]=profile
myArray[R14202].NUMBER[0]=12

myArray[R14203].NAME=R14203
...

edit :

In term of logic, I think that I will have 2 arrays : my associative array and another one to visit my associative array :

myIteratorArray[0]=R14201
myIteratorArray[1]=R14202
myIteratorArray[2]=R14203
myIteratorArray[3]=R14204
...
myArray[R14201].NAME=R14201
myArray[R14201].PROFILE[0]=profile
...

For now I'm just trying to understand and set my array in batch, I learn the langage 3 days ago.

But the fact is : I know with EnableDelayedExtension that I can use 2 variable imbricated, but I don't know if I can have 3 or more imbricated variables.

Thanks to Aacini on this post, I manage to understand a lot of things about arrays in batch.

On the code bellow, into the second for, I don't know how to call the variable.

@echo off
setlocal EnableDelayedExpansion

set i=0
for %%d in (R14201 R14201 R14201 R14202 R14201 R14203 R14203 R14201 R14204) do (
    :: Here I see if myArray[RXXX] is defined
    if not defined myArray[%%d] (
        set /A i=i+1
        set myArray[%%d]=x!i!
        :: Here I set an other array in order to loop on this array, to call myArray[RXXX]
        :: I will call myArray[RXXX] and RXXX will be stored in myIteratorArray[x].
        :: I am sure that myIteratorArray[x] will contain unique value thanks to the if condition
        set myIteratorArray[!i!]=%%d
    )
)

set numberOfJu=%i%

for /L %%i in (1, 1, %numberOfJu%) do (
    ::here the problematic call
    echo !myArray[!myIteratorArray[%%i]!]!
)

Here my questions :

1 - How can I call a variable with multiple imbricated variable like myArray[myIteratorArray[myIndex]] ?

2 - In order to success, what do you think about my logic ?

3 - Do you think it will be possible to do this in batch ? I have no choice for the language.

Thanks in advance !


Solution

  • when a variable that requires delayed expansion to access is composed of additional delayed variables, an additional for loop can be used to access sub variables:

    for /L %%i in (1, 1, %numberOfJu%) do For /f "Delims=" %%u in ("!myIteratorArray[%%i]!") do (
        echo !myArray[%%u]!
    )
    

    As for defining the array with each unique value, findstr can be used to search the relevent group of the array for the existance of that value before adding it to the array during the definition process.

    For an advanced example of handling associative arrays in batch, see here The above is a template for batch RPG games that uses associative arrays to handle all matters related to inventory, with each item having associated values for things such as value, weight dmg/ defence etc that get updated whenever an item is changed by iterating over the #Equipped group.

    the below is a brief script demonstrating how to define an array that can be seached with findstr to achieve an ordered output:

    @Echo off & Cd /d "%~dp0"
    
     Setlocal EnableDelayedExpansion
    :# replace 'source.csv' with the path to your csv file
     For /F "Delims=" %%G in (Source.csv)Do For /F "Tokens=1,3,4 Delims=;," %%1 in ("%%G")Do (
      Echo(!$Refs!|%__APPDIR__%Findstr.exe /c:"%%1" > nul || (
       Set "$Refs=!$Refs! %%1"
      )
      Set /A "%%1[i]+=1"
     rem compare last defined [reference]
      For /f "Delims=" %%v in ('Set /A "!%%1[i]!-1"')Do (
       If not "!Ref[%%1][%%v]!"=="%%3" (
        Set /A "[i]+=1"
        Set "Ref[%%1][!%%1[i]!]=%%3"
        Set /A "Ref[%%1]+=1"
        Set "$Ref[![i]!]%%1[!Ref[%%1]!].%%2=%%3"
       ) Else (
        Set /A %%1[i]-=1
     )))
    
     For %%G in (!$Refs!)Do For /f "Tokens=1,2 Delims==" %%H in ('Set $Ref[ ^| %__APPDIR__%findstr.exe /c:"%%G"')Do (
      For /F "Tokens=2 Delims=." %%1 in ("%%H")Do Echo(Reference: %%G type: %%1 value:%%I
     )
    

    Example output:

    Reference: R14201 type: profile value:15
    Reference: R14201 type: home    value:14
    Reference: R14201 type: profile value:15
    Reference: R14202 type: profile value:12
    Reference: R14203 type: profile value:15
    Reference: R14203 type: profile value:11
    Reference: R14204 type: profile value:12