:CloseArrayGaps :CompactArray function to close gaps in arrays

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
shodan
Posts: 89
Joined: 01 May 2023 01:49

:CloseArrayGaps :CompactArray function to close gaps in arrays

#1 Post by shodan » 18 Sep 2023 20:06

Hello,

I needed functions to close gaps in arrays

Sometimes I need to close all gaps
Other times, I need to close only certain gaps that I have created while leaving other gaps present

So first function you call with

Call :CompactArray YourArrayName

All element gaps will be closed, array must have a defined YourArrayName.ubound value and it will adjust the ubound to the new value

Next function is :CloseArrayGaps, which you call with your array name and then indexes of gaps to close, it accepts numbers as well as anything that my function GetIndexArray can take, example

Call :CloseArrayGaps YourArrayName 4 5 9
Call :CloseArrayGaps YourArrayName 4,5,9
Call :CloseArrayGaps YourArrayName 4,5-7,9

The specified index numbers must be ascending and non repeating, as I do not sort and deduplicate them before processing

Here is the :CompactArray function

Code: Select all

::Usage Call :CompactArray InputArray 
:CompactArray
set "_CompactArray_prefix=_CA
set "_CA_Input=%~1"
call set "_CA_Input_lbound=%%%_CA_Input%.lbound%%"
call set "_CA_Input_ubound=%%%_CA_Input%.ubound%%"
if "[%_CA_Input_lbound%]" EQU "[]" set "_CA_Input_lbound=0"
set /a "_CA_Index=%_CA_Input_lbound%"
set /a "_CA_Previous=%_CA_Index%-1"
if defined %_CA_Input%[%_CA_Index%] ( set /a "_CA_LastEmptyElement=%_CA_Index%+1" ) else ( set /a "_CA_LastEmptyElement=%_CA_Index%" )
:CompactArray-loop
if defined %_CA_Input%[%_CA_Index%] if %_CA_LastEmptyElement% LEQ %_CA_Previous% ( Call :MoveObject %_CA_Input%[%_CA_Index%] %_CA_Input%[%_CA_LastEmptyElement%] & set /a "_CA_LastEmptyElement+=1" )
if defined %_CA_Input%[%_CA_Index%] set /a "_CA_LastEmptyElement=%_CA_Index%+1"
set /a "_CA_Previous+=1" & set /a "_CA_Index+=1"
if %_CA_Index% LEQ %_CA_Input_ubound% GoTo :CompactArray-loop
set /a "%_CA_Input%.ubound=%_CA_LastEmptyElement%-1"
Call :ClearVariablesByPrefix %_CompactArray_prefix% _CompactArray
GoTo :EOF
Here is :CloseArrayGaps

Code: Select all

::Usage Call :CloseArrayGaps ArrayName IndexList1 IndexList2 IndexListN
:CloseArrayGaps
set "_CloseArrayGaps_prefix=_CAG"
set "_CAG_array=%~1" & shift
call set "_CAG_array_ubound=%%%_CAG_array%.ubound%%"
:CloseArrayGaps-arguments
if "[%~1]" NEQ "[]" ( Call :GetIndexArray _CAG_IndexList "%~1" & shift & GoTo :CloseArrayGaps-arguments )
if defined _CAG_IndexList.lbound ( set /a "_CAG_IndexList_index=%_CAG_IndexList.lbound%" ) else ( set /a "_CAG_IndexList_index=0" )
set /a "_CAG_IndexList_ubound=%_CAG_IndexList.ubound%"
call set /a "_CAG_index=%%_CAG_IndexList[%_CAG_IndexList_index%]%%"
set /a "_CAG_next_index=%_CAG_index%+1"
set /a "_CAG_IndexList_index+=1"
if %_CAG_IndexList_index% LEQ %_CAG_IndexList_ubound% ( call set /a "_CAG_next_limit=%%_CAG_IndexList[%_CAG_IndexList_index%]%%" ) else ( set /a "_CAG_next_limit=%_CAG_array_ubound%" )
GoTo :CloseArrayGaps-loop-end
:CloseArrayGaps-loop
setlocal enabledelayedexpansion
set "_CAG_localscope=true"
for /f "tokens=*" %%Z in ('echo.!%_CAG_array%[%_CAG_next_index%]!') do (
															endlocal 
															set %_CAG_array%[%_CAG_index%]=%%Z
															)
if defined _CAG_localscope endlocal
set /a "_CAG_index+=1"
set /a "_CAG_next_index+=1"
:CloseArrayGaps-loop-end
if %_CAG_next_index% LSS %_CAG_next_limit% GoTo :CloseArrayGaps-loop
if %_CAG_IndexList_index% LEQ %_CAG_IndexList_ubound% ( set /a "_CAG_IndexList_index+=1" & set /a "_CAG_next_index+=1" )
if %_CAG_IndexList_index% LEQ %_CAG_IndexList_ubound% ( call set /a "_CAG_next_limit=%%_CAG_IndexList[%_CAG_IndexList_index%]%%" )
if %_CAG_IndexList_index% LEQ %_CAG_IndexList_ubound% ( GoTo :CloseArrayGaps-loop-end ) else ( set /a "_CAG_next_limit=%_CAG_array_ubound%" )
if %_CAG_next_index% LEQ %_CAG_array_ubound% GoTo :CloseArrayGaps-loop
set /a "%_CAG_array%.ubound=%_CAG_index%-1"
Call :ClearVariablesByPrefix %_CloseArrayGaps_prefix% _CloseArrayGaps
GoTo :EOF

ToDo

Allow specifying .suffix
:CompactArray works on objects, :CloseArrayGaps does not because it does not use MoveObject
Maybe allow :CloseArrayGaps to take input of YourArrayName[X] format, in addition of arrayname indexarray
Support for arrayname.selection, to include indexarray along with the array itself in the .selection object


Here is a DEMO function called mini-DEMO

Code: Select all

:mini-DEMO

Call :ClearVariablesByPrefix myarray
set myarray[0]=element 0
set myarray[1]=element 1
set myarray[2]=element 2
set myarray[3]=element 3
set myarray[4]=element 4
REM set myarray[5]=element 5
REM set myarray[6]=element 6
REM set myarray[7]=element 7
set myarray[8]=element 8
set myarray[9]=element 9
set myarray[10]=element 10
set myarray.ubound=10

echo.&echo Printing myarray&echo.
REM call :echoarray myarray LINENUMBERS
call :echoarray myarray SHOWVARNAME
call :CloseArrayGaps myarray 5,6,7
echo.&call :echoarray myarray LINENUMBERS

Call :ClearVariablesByPrefix myarray
set myarray[0]=element 0
set myarray[1]=element 1
set myarray[2]=element 2
set myarray[3]=element 3
set myarray[4]=element 4
REM set myarray[5]=element 5
REM set myarray[6]=element 6
REM set myarray[7]=element 7
set myarray[8]=element 8
set myarray[9]=element 9
set myarray[10]=element 10
set myarray.ubound=10

echo.&echo Printing myarray&echo.
call :echoarray myarray LINENUMBERS
call :CompactArray myarray
echo.&call :echoarray myarray LINENUMBERS

Call :ClearVariablesByPrefix myarray
set myarray[0]=element 0
REM set myarray[1]=element 1
set myarray[2]=element 2
set myarray[3]=element 3
REM set myarray[4]=element 4
set myarray[5]=element 5
set myarray[6]=element 6
REM set myarray[7]=element 7
set myarray[8]=element 8
set myarray[9]=element 9
set myarray[10]=element 10
set myarray.ubound=10

echo.&echo Printing myarray&echo.
call :echoarray myarray LINENUMBERS
call :CloseArrayGaps myarray 1,4,7
echo.&call :echoarray myarray LINENUMBERS

Call :ClearVariablesByPrefix myarray
set myarray[0]=element 0
REM set myarray[1]=element 1
set myarray[2]=element 2
set myarray[3]=element 3
REM set myarray[4]=element 4
set myarray[5]=element 5
set myarray[6]=element 6
REM set myarray[7]=element 7
set myarray[8]=element 8
set myarray[9]=element 9
set myarray[10]=element 10
set myarray.ubound=10

echo.&echo Printing myarray&echo.
call :echoarray myarray LINENUMBERS
call :CompactArray myarray
echo.&call :echoarray myarray LINENUMBERS

GoTo :EOF
Here is the output of that function

Code: Select all

Printing myarray

myarray[0]:element 0
myarray[1]:element 1
myarray[2]:element 2
myarray[3]:element 3
myarray[4]:element 4
myarray[5]:
myarray[6]:
myarray[7]:
myarray[8]:element 8
myarray[9]:element 9
myarray[10]:element 10

0:element 0
1:element 1
2:element 2
3:element 3
4:element 4
5:element 8
6:element 9
7:element 10

Printing myarray

0:element 0
1:element 1
2:element 2
3:element 3
4:element 4
5:
6:
7:
8:element 8
9:element 9
10:element 10

0:element 0
1:element 1
2:element 2
3:element 3
4:element 4
5:element 8
6:element 9
7:element 10

Printing myarray

0:element 0
1:
2:element 2
3:element 3
4:
5:element 5
6:element 6
7:
8:element 8
9:element 9
10:element 10

0:element 0
1:element 2
2:element 3
3:element 5
4:element 6
5:element 8
6:element 9
7:element 10

Printing myarray

0:element 0
1:
2:element 2
3:element 3
4:
5:element 5
6:element 6
7:
8:element 8
9:element 9
10:element 10

0:element 0
1:element 2
2:element 3
3:element 5
4:element 6
5:element 8
6:element 9
7:element 10
Here is the full DEMO file which includes to more demo functions :CloseArrayGaps-DEMO :CompactArray-DEMO
As well as all the support functions for these demos

Note that :CloseArrayGaps depends on :GetIndexArray and :ClearVariablesByPrefix
While :CompactArray depends on :MoveObject and :ClearVariablesByPrefix
CloseArrayGaps-DEMO.zip
(4.54 KiB) Downloaded 1000 times

Post Reply