【问题标题】:Batch - Removing elements from an Array批处理 - 从数组中删除元素
【发布时间】:2016-02-23 20:54:46
【问题描述】:

我相信这个问题的答案应该很简单。我从某个地方获取目录列表并将它们存储到文本文档中。然后我读取文本文档名称并将它们存储到一个数组中。在此过程结束时,我希望擦除数组中的所有条目。

我想这样做的原因是因为我要遍历几个文件夹位置并将它们存储到同一个数组中。但是,当我每次都不清除数组时,当我稍后尝试将其打印出来时,它似乎给了我各种各样的麻烦。

每次我去填写下一个文件夹时,我都需要一个新的数组。

REM **************************************************************************
                REM this part needs to delete the value but doesnt
                set !array[%arraywiper%]!=0

REM **************************************************************************  

这是我遇到的问题的一个示例。可以运行下面的代码来看看我在说什么。

ECHO OFF & setLocal EnableDELAYedExpansion
cls

REM creates folder for text doc
IF EXIST "c:\TEMP" (echo.) else (md c:\TEMP\)

REM Scans C:\Program Files (x86) and stores into a text doc
(for /f "delims=" %%a in ('dir /a:D-H-S /on /b "C:\Program Files (x86)"') do echo %%a)> c:\TEMP\dork_array_wipe.txt

REM Counts the folders in the text doc
for /d %%a in ("C:\Program Files (x86)\"*) do ( 
set /a locationcount+=1 
)

REM Stores the values from the doc into an array
for /F "usebackq delims=" %%a in ("c:\TEMP\dork_array_wipe.txt") do (
set /A i+=1
call set array[%%i%%]=%%a
)

set arraywiper=1

:Arraywipeloop19

IF %arraywiper%==%locationcount% GOTO Arraywipecomplete19 else (

                    REM Prints array to show value entered array
                    echo array (%arraywiper%): !array[%arraywiper%]!


    REM **************************************************************************
                    REM this part needs to delete the value but doesnt
                    set !array[%arraywiper%]!=0

    REM **************************************************************************              

                    Set /a arraywiper+=1

                    REM Prints out array in question to veryify change took place
                    echo array (%arraywiper%): !array[%arraywiper%]!
                    GOTO Arraywipeloop19
                    )

:Arraywipecomplete19


pause

先生。 Rojo 给了我一个很好的解决这个问题的方法。这是其工作原理的一个示例。

@echo off
setlocal

set "array[0]=foo"
set "array[1]=bar"
set "array[2]=baz"
set "array[3]=qux"
set "array[4]=quux"
set "array[5]=corge"

echo.
echo first printout

echo %array[0]%, %array[1]%, %array[2]%, %array[3]%, %array[4]%, %array[5]%
pause


rem // starting with element 3, delete 2 elements and insert 3 new
call :splice array 3 2 grault garply waldo

echo.
echo second printout

echo %array[0]%, %array[1]%, %array[2]%, %array[3]%, %array[4]%, %array[5]%, %array[6]%, %array[7]%
pause
call :splice array 0 

REM set array[

REM goto :EOF

echo.
echo third printout

echo %array[0]%, %array[1]%, %array[2]%, %array[3]%, %array[4]%, %array[5]%, %array[6]% 

pause

set "array[0]=foo"
set "array[1]=bar"
set "array[2]=baz"
set "array[3]=qux"
set "array[4]=quux"
set "array[5]=corge"

echo.
echo fourth printout

echo %array[0]%, %array[1]%, %array[2]%, %array[3]%, %array[4]%, %array[5]%, %array[6]% 

pause




:splice <array_name> <startIDX> [<deleteCount> [<item1> [<item2> [...]]]]
rem // works like JavaScript Array.prototype.splice()
rem // https://developer.mozilla.org/en-US/search?q=Array.prototype.splice()
setlocal enabledelayedexpansion
set /a idx = 0, argskip = 0, inserted = 0, orig_ubound = -1
if "%~3"=="" (set /a "resume = 1 << 30") else set /a resume = %~2 + %~3
for /f "tokens=1* delims==" %%I in ('set %~1[') do (
    set /a orig_ubound += 1
    if !idx! lss %~2 (
        set "tmp[!idx!]=%%J"
        set /a ubound = idx, idx += 1
    ) else (
        if !inserted! equ 0 (
            for %%# in (%*) do (
                set /a argskip += 1, inserted = 1
                if !argskip! gtr 3 (
                    set "tmp[!idx!]=%%~#"
                    set /a ubound = idx, idx += 1, resume += 1
                )
            )
        )
        if !idx! geq !resume! (
            set "tmp[!idx!]=%%J"
            set /a ubound = idx, idx += 1
        ) else set /a resume -= 1
    )
)
set "r=endlocal"
for /f "tokens=1* delims=[" %%I in ('2^>NUL set tmp[') do (
    set "r=!r!&set "%~1[%%J""
)
for /L %%I in (%idx%,1,%orig_ubound%) do set "r=!r!&set "%~1[%%I]=""
%r%&exit/b

【问题讨论】:

  • 去掉!s 中的set 语句。
  • setlocal 在构建阵列之前。只需执行set array 即可输出所有数组值。当你想销毁数组时,endlocal.
  • @SomethingDark 摆脱!的除了破坏代码什么也没做。如果我删除!的代码不再输出任何东西。我尝试只删除数组清除部分中的 !,但它什么也没做。
  • @rojo 我不完全明白你要我做什么。举个例子会很有帮助。

标签: arrays batch-file


【解决方案1】:

这是我上面评论的一个例子,展示了使用 setlocalendlocal 来忘记变量。

@echo off
setlocal

set idx=0

rem // populate array
setlocal enabledelayedexpansion
for /f "delims=" %%I in ('dir /b /a:-d') do (
    set "array[!idx!]=%%~nxI"
    set /a idx += 1
)

rem // display array
set array[

rem // destroy array
endlocal

rem // result
set array[

或者,如果您更喜欢循环遍历数组元素而不是使用set 来输出它们的值:

@echo off
setlocal

set idx=0

rem // populate array
setlocal enabledelayedexpansion
for /f "delims=" %%I in ('dir /b /a:-d') do (
    set "array[!idx!]=%%~nxI"
    set /a ubound = idx, idx += 1
)

rem // display array
for /L %%I in (0,1,%ubound%) do echo array[%%I]: !array[%%I]!

rem // destroy array
endlocal

rem // result
echo %array[0]%

编辑:如果您必须使用索引数组方法来操作变量集合,我编写了一个 :splice 函数,其工作方式类似于 JavaScript 的 Array.prototype.splice()。您可以使用它来删除元素、插入元素、两者的组合,甚至可以根据需要清除整个数组。 (只需call :splice arrayname 0 即可取消设置数组中的所有元素。)

@echo off
setlocal

set "array[0]=foo"
set "array[1]=bar"
set "array[2]=baz"
set "array[3]=qux"
set "array[4]=quux"
set "array[5]=corge"

rem // starting with element 3, delete 2 elements and insert 3 new
call :splice array 3 2 grault garply waldo

set array[

goto :EOF

:splice <array_name> <startIDX> [<deleteCount> [<item1> [<item2> [...]]]]
rem // works like JavaScript Array.prototype.splice()
rem // https://developer.mozilla.org/en-US/search?q=Array.prototype.splice()
setlocal enabledelayedexpansion
set /a idx = 0, argskip = 0, inserted = 0, orig_ubound = -1
if "%~3"=="" (set /a "resume = 1 << 30") else set /a resume = %~2 + %~3
for /f "tokens=1* delims==" %%I in ('set %~1[') do (
    set /a orig_ubound += 1
    if !idx! lss %~2 (
        set "tmp[!idx!]=%%J"
        set /a ubound = idx, idx += 1
    ) else (
        if !inserted! equ 0 (
            for %%# in (%*) do (
                set /a argskip += 1, inserted = 1
                if !argskip! gtr 3 (
                    set "tmp[!idx!]=%%~#"
                    set /a ubound = idx, idx += 1, resume += 1
                )
            )
        )
        if !idx! geq !resume! (
            set "tmp[!idx!]=%%J"
            set /a ubound = idx, idx += 1
        ) else set /a resume -= 1
    )
)
set "r=endlocal"
for /f "tokens=1* delims=[" %%I in ('2^>NUL set tmp[') do (
    set "r=!r!&set "%~1[%%J""
)
for /L %%I in (%idx%,1,%orig_ubound%) do set "r=!r!&set "%~1[%%I]=""
%r%&exit/b

【讨论】:

  • 你知道删除数组中一个元素的方法吗?我读到这可能很困难。
  • 只是set "array[!idx!]="。批处理语言实际上并没有传统意义上的正确 Array 对象。您实际上是在设置 20 个具有相似名称(给或取)的变量,而不是用多个值填充单个对象。这一点都不难。 set "array[5]=" 会将名为 %array[5]% 的变量设置为空 - 因此将取消定义它。如果你想重新索引你的可疑引用“数组”,可能会很困难。这将是一个挑战,并且(尽管并非不可能)更适合不同的脚本语言。
  • 所以经过进一步测试。我已经决定使用 set local 和 end local 给出的解决方案不是真正的解决方案。我不再将此视为解决方案的原因是因为使用此方法您无法从数组中提取任何信息。如果您尝试存储该数组中的任何变量,则在使用 end local 时它将全部被销毁。我可以将信息导出到文本文档,然后阅读该信息,但这是一种解决方法,并不是我真正想要的。
  • @Magnes3d 只是为了好玩,前几天晚上我写了一个:splice 函数,这可能是你正在寻找的。看看你是否觉得我的编辑有用。
  • 不错的 Bat_Array.prototype.splice() ! +1
【解决方案2】:

也可以通过列表结合索引变量来模拟批处理数组,以将元素与索引值匹配

下面使用宏来演示如何对列表类型的数组进行模拟:

  • 修改原始列表或将结果返回到克隆列表
  • 在提供的索引处拼接新元素
  • 按索引号提取特定元素
  • 从列表中删除元素。

每个宏都通过以下组合接受 Args:

  • 子串修改

    • array varname 和array clone / return varname 替换{e}
    • 拼接宏的第二个 Arg 是要插入新值的索引
  • For循环If else构造

    • 捕获索引号以采取行动。

使用宏和列表而不是调用函数或将大量值分配给关联变量可以大大加快执行速度。

Splice 宏包含一种验证方法

@Echo off

rem /* Macro Definition - Arg order mandatory in each macro. */
(Set \n=^^^
%= Newline var for macro definitions. Do Not Modify =%
)
::: Reserved Variable names used for Macro's:
::: \n Splice Extract Remove Groupname Insert Prepend Append Rvar RV cArr
::: {i} {i#} Tokens

rem /* Usage: %Splice:{e}={ListVarName}{Insertion Index}{OPTIONAL-NewListVarname}% */
Set Splice=For %%n in (1 2)do if %%n==2 (%\n%
 For /F "Tokens=1,2,3 Delims={}" %%1 in ("{e}") Do (%\n%
  Set "Groupname=%%1"%\n%
  Set "{i#}=%%2"%\n%
  Set "cArr=%%3"%\n%
 )%\n%
 Set "Prepend="%\n%
 Set "Append="%\n%
 Set "{i}=0"%\n%
 For %%G in (!Groupname!)Do For %%E in (!%%G!)Do (%\n%
  If !{i}! LSS !{i#}! (%\n%
   If "!Prepend!" == "" (Set "Prepend=%%E")Else (Set "Prepend=!Prepend! %%E")%\n%
  )%\n%
  If !{i}! GEQ !{i#}! (%\n%
   If "!Append!" == "" (Set "Append=%%E")Else (Set "Append=!Append! %%E")%\n%
  )%\n%
  Set /A "{i}+=1"%\n%
 )%\n%
  If Not "!cArr!" == "" (Set "!cArr!=!Prepend! !Insert! !Append!")Else (Set "!Groupname!=!Prepend! !Insert! !Append!")%\n%
)Else Set Insert=

rem /* Usage: %Remove:{e}={ListVarName}{OPTIONAL-NewListVarname}% Index/es to be removed as Integer list */
Set Remove=For %%n in (1 2)do if %%n==2 (%\n%
 For /F "Tokens=1,2 Delims={}" %%1 in ("{e}") Do (%\n%
  Set "Groupname=%%1"%\n%
  Set "cArr=%%2"%\n%
  Set "Rvar="%\n%
 )%\n%
 Set "Prepend="%\n%
 Set "Append="%\n%
 Set "{i}=0"%\n%
 For %%G in (!Groupname!)Do For %%E in (!%%G!)Do (%\n%
  Set /A "{i}+=1"%\n%
  Set "{i#}=1"%\n%
  For %%t in (!Tokens!)Do If %%t EQU !{i}! Set "{i#}=0"%\n%
  If !{i#}! EQU 1 (%\n%
   If "!Rvar!" == "" (Set "Rvar=%%E")Else (Set "Rvar=!Rvar! %%E")%\n%
  )%\n%
 )%\n%
 If Not "!cArr!" == "" (Set "!cArr!=!Rvar!")Else (Set "!Groupname!=!Rvar!")%\n%
)Else Set Tokens=

rem /* Usage: %Extract:{e}={ListVarName}{OPTIONAL-ReturnVarName[Default - RV ]}%Index/es to be extracted as Integer list */
Set Extract=For %%n in (1 2)Do if %%n==2 (%\n%
 For /F "Tokens=1,2 Delims={}" %%1 in ("{e}") Do (%\n%
  Set "Groupname=%%1"%\n%
  Set "Rvar=%%2"%\n%
  If "!Rvar!" == "" ( Set "Rvar=RV" )%\n%
 )%\n%
 Set "{i}=0"%\n%
  Set "!Rvar!="%\n%
 For %%G in (!Groupname!)Do For %%E in (!%%G!)Do (%\n%
  Set /A "{i}+=1"%\n%
  For %%v in (!{i#}!)Do If !{i}! EQU %%v (%\n%
   For %%r in (!Rvar!)Do If "!%%r!" == "" ( Set "!Rvar!=%%E" )Else ( Set "!Rvar!=!%%r! %%E" )%\n%
  )%\n%
 )%\n%
)Else Set {i#}=

rem /* Delayed Expansion Must be enabled to expand macro's */ ::: EXAMPLE USAGES:
Setlocal EnableDelayedExpansion
Set List=1 2 3 4 5 6 7 8
Set list
Echo/rem /* insert new elements. Example = insert "9 9" after the 3rd element. */
%Splice:{e}={List}{3}%9 9
Set List
Echo/rem /* extract element/s. example = 1st 4th and 6th elements */
%Extract:{e}={List}{YourReturnVar}%1 4 6
Set YourReturnVar
Echo/rem /* remove elements from list. example=remove the 1st 4th and 6th elements */
%Remove:{e}={List}%1 4 6
Set List
Echo/rem /* Clone existing list; inserting elements . Example = insert previously extracted elements
Echo/rem    at the max index [ from the last {i} index returned ] */
%Splice:{e}={List}{!{i}!}{clone}%!YourReturnVar!
Set Clone

示例输出:

【讨论】:

    猜你喜欢
    • 2011-10-31
    • 1970-01-01
    • 2022-01-13
    • 2016-03-08
    • 2017-09-13
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多