『楼 主』:
谈谈for循环的效率问题:
大家都知道for是批处理中最强大的命令,通过for循环和for镶嵌大循环可以完成很多
大批量的工作如:
for /l %%i in (1,1,10000) do echo %%i >>a.txt 就能在几秒中内实现把1-1000的整数输入到文本中(比你一个个写效率高了N倍)
又如:
for /l %%i in (1,1,9) do (
for /l %%j in (1,1,9) do (
echo %%i+%%j >>a.txt
) 这段代码实现的是将1+1 1+2 .....1+9 2+1 2+2....2+9.........9+1 9+2.....9+9输入到
文本中(经过改写就可以生成九九加法表)。
但在批处理中使用for镶嵌大循环应注意其工作效率,如:
@echo off
for /f "tokens=*" %%i in ('findstr /n .* 1.txt') do (
for /f "tokens=*" %%j in ('findstr /n .* 2.txt') do (
set var=%%i
set str=%%j
setlocal enabledelayedexpansion
if "!var:~,1!"=="!str:~,1!" echo !var:~2,50!&echo !str:~2,50!
endlocal
)
) 这是我早几天写下的一个代码,实现的是对1.txt和2.txt(行数相同)的跳行输出,就
是先输出1.txt的第一行再输出2.txt的第一行,然后依次类推进行跳行输出。这段代码虽能
完成这项任务,但出现了效率的大问题。它工作时首先读取1.txt的第一行和再将其行号也
就是1在2.txt的各行行号进行比对,如果行号相同就输出1.txt的第一行再输入2.txt的第一
行,然后又返回提取1.txt的第二行将行号也就是2在2.txt中进行比对行号,如行号相同同
上输出,以此类推一直到比对完1.txt和2.txt中所有的行号。
如果1.txt和2.txt各有100行的话,那就是要比对100*100=10000次(for镶嵌中的次数
是以乘来计算的),本来最快的比对次数应是100+100=200次,足见效率有多低。
那么怎么来解效率低的问题,这就是我要下面要讲的了:
如果在for循环中加入判断并使用call调用语句的话,将会大大提高循环的效率,如上
面那段代码可改写为:
@echo off
set n=-1
for /f "delims=" %%i in ('findstr /n .* 1.txt') do (
set a=%%i
set /a n+=1
set /a v=n+1
setlocal enabledelayedexpansion
set a=!a:*:=!&echo !a!&call :lp
endlocal
)
pause&goto :eof
:lp
set m=skip=!n!
if "!m!"=="skip=0" set m=
for /f "delims= %m%" %%i in ('findstr /n .* 2.txt') do (
set b=%%i
if "!b:~,1!"=="!v!" set b=!b:*:=!&echo !b!&goto :eof
if "!b:~,2!"=="!v!" set b=!b:*:=!&echo !b!&goto :eof
if "!b:~,3!"=="!v!" set b=!b:*:=!&echo !b!&goto :eof
) 这段代码由于先前设置了数值n和v的递加,第一次call调用时n为0v为1(第二次n为1v为2),先利用skip=%n%命令逐次逐行忽略对b.txt行号的比较,同时再加入if命令对行号进行比对(注意这时首行在逐次下推),一旦发现了等于v的行号(其实就是经过skip命令忽略后的首行行号)就显示输出并返回第一个for循环(中间还有个变量替换),如此也就是每次只对b.txt的一行进行比对。
虽然看上去代码要复杂了,但效率提到了最高,降到最少的比对次数200次,所以我们在使用for镶嵌大循环时一定要注意效率的问题,在达到目的情况下力求最高的循环效率!
大家还要注意在for循环中切不可滥用findstr可多用if,经jvive兄弟的测试100000次if 否定判断用时1.63秒, 执行效率61349次/秒,而findstr .* 一个10行的文本100次 用时3.55秒, 执行效率28.169次/秒,同时本人对jvive兄弟这种认真研究的精神深表钦佩。
因此,再次将以上代码提效修改如下:
@echo off
set n=-1
for /f "delims=" %%i in (1.txt) do (
call :lp %%i
)
pause&goto :eof
:lp
set /a n+=1
set m=skip=%n%
if "%m%"=="skip=0" set m=
for /f "delims= %m%" %%i in (2.txt) do (
echo %1 %%i&goto :eof
) 如此才算得上是真正的高效的代码。
[ Last edited by zw19750516 on 2008-4-3 at 12:20 PM ]
|