【bat】配列 array.bat

# update

<details><summary>20240405 - viewSome追加 / forSome</summary>

 **viewSome** 
複数の配列を **view** できるメソッド

 **forSome** 
 **使い方** に記述

</details>

<details><summary>20240404 - 戻り値を格納する変数の変更 / unshift刷新 / methods追加 / init追加</summary>

 **array.ans** を廃止、配列ごとに **[VarName].ans** を設定
更新したメソッド：pop / range / at / join

```bat
%ARRAY% array name 0 1 2 3 4 5
%ARRAY% at name 2
echo %name.ans%
```

 **unshift** 
上記更新のネックになっていた ので、記述を刷新
戻り値も廃止

 **methods** 
使えるメソッドの一覧表示

**init** 
変数 **ARRAY** に `call %~dpnx0` を代入
bat内で使用される変数 **array.???** を初期化
</details>

<details><summary>20240318 - foreach</summary>

**使い方** に、**foreach** について記述
**array.bat** に置きたかったけど断念
</details>

<details><summary>20240314 - shove追加 / at更新</summary>


**shove** は、pushの追加する要素数を一つだけにしたメソッドです
その分、**array** よりシンプルな処理です

```diff_batchfile
rem at - 20240314
:_at
setlocal enabledelayedexpansion
set n=%~2
+ set m=%~3
if %n% lss 0 set /a n = !%~1.size! + %n%
+ if defined m set /a n += %m%
endlocal & call set array.ans=%%%~1.%n%%%
exit /b
```

```bat
rem %ARRAY% at [VarName] [Index] [incr]

%ARRAY% at var -3 -1
echo %array.ans%
```

**[incr]** の数値分 **[Index]** を増減させて取得
上記例では、**-4** を指定したのと同じ
</details>

<details><summary>20240311 - pop追加 / range追加 / array修正</summary>

**array**内の変数名 **__size** を **array.size**に変更

```bat
%ARRAY% pop var
echo %array.ans%
```

説明不要の**pop**
**shift**の追加予定は無し


```bat
rem range [VarName] [StartIndex] [EndIndex]
%ARRAY% range var -1 1
echo %array.ans%
```

[StartIndex]から[EndIndex]までの範囲を**view**と同様に表示
**array.ans**には**join**と同様の結果が格納
[StartIndex]の数値のほうが大きいと逆順になる
</details>

<details><summary>20240305 - unshift修正</summary>


```diff_batchfile
rem unshift
:_unshift
setlocal enabledelayedexpansion
set joining=
- set el=%*
- set el=!el:*%~1 =!
- for %%i in (%el%) do (
+ for %%i in (%*) do (
	set joining=!joining!,"%%~i"
)
- set joining=!joining:*,=!
+ set joining=!joining:*,"%~1",=!
call :_join %~1
endlocal & set array.ans=%joining%,%array.ans%
- set %~1.size=
+ set %~1.size=0
call :_array %~1 %array.ans%
exit /b
```
</details>

# つぶやき

もう少し気軽に配列を扱えないものかと思い作ってみた
まだまだ、検証不足
想定は小規模な配列
遅延展開を意識せず配列を扱いたい人向け

**array.bat**を通さず操作した時、**size**の更新がされないのが難点


# array.bat

~~戻り値 は、変数 array.ans に格納~~
**戻り値** は、変数 **[VarName].ans**  に格納


<details><summary>本体</summary>


```bat:array.bat
@echo off

call :_%*
exit /b


rem init
:_init
call :_delete array
set ARRAY=call %~dpnx0
exit /b


rem methods
:_methods
echo.
echo LIST of METHODS
echo.
echo 	init
echo 	methods
echo 	array	[Var] [Args...]
echo 	shove	[Var] [Arg]
echo 	unshift	[Var] [Args...]
echo 	pop	[Var]
echo 	at	[Var] [Index [Increase]]
echo 	view	[Var [rev]]
echo 	viewSome	[Var [Var [Var...]]]
echo 	join	[Var [rev]]
echo 	range	[Var] [SartIndex [EndIndex]]
echo 	delete	[Var]
echo.
echo [Var].ans
echo.
echo 	range	joined string
echo 	join	joined string
echo 	pop	last element
echo 	at	element of target index
echo.
exit /b


rem array
:_array
call set array.size=%%%~1.size%%
if "%array.size%" == "" (
	set %~1=[[array]]
	set %~1.size=0
)
set array.args=%*
call set array.args=%%array.args:*%~1 =%%
for %%i in (%array.args%) do (
	call set %~1.%%%~1.size%%="%%~i"
	set /a %~1.size += 1
)
set array.args=
set array.size=
exit /b



rem shove - 20240314
:_shove
call set array.size=%%%~1.size%%
if not defined array.size (
	set %~1=[[array]]
	set array.size=0
)
set %~1.%array.size%="%~2"
set /a %~1.size += 1
exit /b


rem unshift
:_unshift
set array.add=-1
for %%i in (%*) do set /a array.add += 1
if %array.add% equ 0 exit /b
call set array.from=%%%~1.size%%
if not defined array.from set %~1=[[array]]

set /a array.from -= 1
set /a array.to = %array.from% + %array.add%
set /a %~1.size = %array.to% + 1

:unshift.move
if %array.from% geq 0 (
	call set %~1.%array.to%=%%%~1.%array.from%%%
	set /a array.from -= 1
	set /a array.to -= 1
	goto :unshift.move
)
set array.idx=0
:unshift.add
if %array.add% gtr %array.idx% (
	call set %~1.%array.idx%="%~2"
	set /a array.idx += 1
	shift /2
	goto :unshift.add
)
exit /b


rem view
:_view
setlocal enabledelayedexpansion
if "%~2" == "rev" (
	set /a start=!%~1.size! - 1
	set incre=-1
	set end=0
) else (
	set start=0
	set incre=1
	set /a end=!%~1.size! - 1
)
for /l %%i in (%start%,%incre%,%end%) do (
	echo 	%%i	!%~1.%%i!
)
endlocal
exit /b

rem viewSome
:_viewSome
setlocal enabledelayedexpansion
set end=0
for %%i in (%*) do (
	set size=!%%~i.size!
	if !end! lss !size! set end=!size!
)
set /a end -= 1
for /l %%i in (0,1,%end%) do (
	set row=	%%i
	for %%m in (%*) do (
		set elm=!%%~m.%%i!
		if not defined elm set elm=empty
		set row=!row!	!elm!
	)
	echo !row!
)
endlocal
exit /b


rem at - 20240314
:_at
setlocal enabledelayedexpansion
set n=%~2
set m=%~3
if %n% lss 0 set /a n = !%~1.size! + %n%
if defined m set /a n += %m%
endlocal & call set %~1.ans=%%%~1.%n%%%
exit /b


rem join
:_join
setlocal enabledelayedexpansion
if "%~2" == "rev" (
	set /a start=!%~1.size! - 1
	set incre=-1
	set end=0
) else (
	set start=0
	set incre=1
	set /a end=!%~1.size! - 1
)
set joining=
for /l %%i in (%start%,%incre%,%end%) do (
	set joining=!joining!,!%~1.%%i!
)
set joining=!joining:*,=!
endlocal & set %~1.ans=%joining%
exit /b


rem delete
:_delete
set %~1=
for /f "usebackq delims== tokens=1" %%a in (`set %~1.`) do set %%a=
exit /b


rem pop - 20240311
:_pop
set /a %~1.size -= 1
setlocal enabledelayedexpansion
set n=!%~1.size!
endlocal & call set %~1.ans=%%%~1.%n%%%
call set %~1.%%%~1.size%%=
exit /b



rem range - 20240311
:_range
setlocal enabledelayedexpansion
set size=!%~1.size!
set start=%~2
set end=%~3
set incr=1
set joining=

if not defined start set start=0
if not defined end set /a end = %size% - 1

if %start% lss 0 set /a start += %size%
if %end% lss 0 set /a end += %size%

if %start% geq %size% set /a start = %size% - 1
if %end% geq %size% set /a end = %size% - 1

if %start% gtr %end% set incr=-1
for /l %%i in (%start%,%incr%,%end%) do (
	echo 	%%i	!%~1.%%i!
	set joining=!joining!,!%~1.%%i!
)
set joining=!joining:*,=!
endlocal & set %~1.ans=%joining%
exit /b



```


</details>



# 使い方


## 準備


```bat:
@echo off
set ARRAY=call %~dp0array.bat

rem %ARRAY% [Method] [VarName] [Args...]
```

## array
配列を生成します
```bat:
%ARRAY% array var "" a b c
set var
```
```:result
var=[[array]]
var.0=""
var.1="a"
var.2="b"
var.3="c"
var.size=4
```
このような変数が生成されます

配列が既に存在する時は**push**します

```bat
%ARRAY% array var d e f ""
set var
```

```:result
var=[[array]]
var.0=""
var.1="a"
var.2="b"
var.3="c"
var.4="d"
var.5="e"
var.6="f"
var.7=""
var.size=8
```

## unshift
前方に追加します

~~副産物として変数**array.ans**に
追加要素も含め**join**された結果が格納されます~~
```bat
%ARRAY% unshift var 0 1 "" 2 3
set var
```

```:result
var=[[array]]
var.0="0"
var.1="1"
var.10="e"
var.11="f"
var.12=""
var.2=""
var.3="2"
var.4="3"
var.5=""
var.6="a"
var.7="b"
var.8="c"
var.9="d"
var.size=13
```

## view
一覧表示します
indexとelementをTABで区切ってます
```bat
%ARRAY% view var
```

```:result
	0	"0"
	1	"1"
	2	""
	3	"2"
	4	"3"
	5	""
	6	"a"
	7	"b"
	8	"c"
	9	"d"
	10	"e"
	11	"f"
	12	""
```
VarNameの後に**rev**を付けると逆順に表示します
```bat
%ARRAY% view var rev
```

```:result
	12	""
	11	"f"
	10	"e"
	9	"d"
	8	"c"
	7	"b"
	6	"a"
	5	""
	4	"3"
	3	"2"
	2	""
	1	"1"
	0	"0"
```

## viewSome
複数の配列を一覧表示します
要素が無い場合は **empty** 表示
**rev** は無し

```bat
%ARRAY% array var1 0 1
%ARRAY% array var2 2 3 4 5 6 7
%ARRAY% array var3 8
%ARRAY% array var4 9 0 a b c
%ARRAY% array var5 d e f g

%ARRAY% viewSome var1 var2 var3 var4 var5
```

```:result
        0       "0"     "2"     "8"     "9"     "d"
        1       "1"     "3"     empty   "0"     "e"
        2       empty   "4"     empty   "a"     "f"
        3       empty   "5"     empty   "b"     "g"
        4       empty   "6"     empty   "c"     empty
        5       empty   "7"     empty   empty   empty
```


## at
指定したindexの要素を取得します
**-1**を指定すると末尾の要素を取得します
結果は変数 **[VarName].ans** に格納されます
update / [incr] の数値分 [Index] を増減させて取得

```bat
rem %ARRAY% at [VarName] [Index] [incr]

%ARRAY% at var -2
echo %var.ans%

%ARRAY% at var 1
echo %var.ans%

%ARRAY% at var -3 -1
echo %var.ans%
```

```:result
"f"
"1"

```


## join
全ての要素を一つの文字列に連結します
区切り文字は**カンマ**固定です
結果は変数 **[VarName].ans** に格納されます
```bat
%ARRAY% join var
echo %var.ans%
```

```:result
"0","1","","2","3","","a","b","c","d","e","f",""
```

VarNameの後に**rev**を付けると逆順に連結します
```bat
%ARRAY% join var rev
echo %var.ans%
```

```:result
"","f","e","d","c","b","a","","3","2","","1","0"
```


## delete
配列を削除します
```bat
%ARRAY% delete var
set var
```

```:result
環境変数 var が定義されていません
```

## for-loop

```bat
%ARRAY% array var2 a b c d e f g

%ARRAY% join var2
echo # element
for %%i in (%var2.ans%) do (
	echo # %%~i
)

echo # index	element
for /f "usebackq delims=	 tokens=1,2" %%a in (`%ARRAY% view var2`) do  (
	echo # %%~a	%%~b
)
```
## foreach - 20240318

**foreach** と違うbatに呼び出したいサブルーチンがあるとエラーになるため、**array.bat内ではなく、実装させたいbat内** に、サブルーチンとして記述する


```bat:main.bat
set ARRAY=call %~dp0array.bat
%ARRAY% array var a b c d

rem call :foreach [VarName] [Label]
call :foreach var subroutine

echo %m_0% %m_1% %m_2% %m_3%
pause>nul


:subroutine
rem %1 : element
rem %2 : index
set m_%2=%1
exit /b

rem foreach
:foreach
call set /a array.size = %%%~1.size%% - 1
for /l %%i in (0,1,%array.size%) do (
	call :%~2 %%%~1.%%i%% %%i
)
exit /b
```

## forSome
**foreach** 同様、実行したいサブルーチンと同じbatに置く
**ARRAY** に `call %~dp0array.bat` を代入していなければ書き換える
他のメソッドと違い、ラベル名を先に指定する

```bat
call :forSome test var1 var2 var3
set sum.

goto :end

:test
set /a sum.%~1 = %~2 + %~3 + %~4
exit /b

rem forSome [Label] [Var [Var [Var...]]]
:forSome
set array.args=%*
call set array.args=%%array.args:*%~1 =%%
for /f "usebackq delims=	 tokens=*" %%a in (`%ARRAY% viewSome %array.args%`) do call :%~1 %%~a
exit /b

:end
pause
```

## get size

```bat
echo %var2.size%
```