中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
作者:
标题: 谈谈for循环的效率问题: 上一主题 | 下一主题
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『楼 主』:  谈谈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 ]



批处理之家新域名:www.bathome.net
2008-4-2 23:44
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
zh159
金牌会员




积分 3687
发帖 1467
注册 2005-8-8
状态 离线
『第 2 楼』:  

能不用findstr的地方最好不要用



2008-4-3 00:24
查看资料  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 3 楼』:  



  Quote:
Originally posted by zh159 at 2008-4-3 00:24:
能不用findstr的地方最好不要用

为什么



批处理之家新域名:www.bathome.net
2008-4-3 00:28
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
zh159
金牌会员




积分 3687
发帖 1467
注册 2005-8-8
状态 离线
『第 4 楼』:  

findstr先要读取完文件再传输给for,比for直接读取文件需要的时间稍长
测试150行文件:
@echo off
:loop
set time_=%time%
if not %time_:~-4% == 0.00 goto loop
for /f "tokens=1,2" %%i in ('findstr /n .* 1.txt') do echo %%i %%j
echo %time_%
echo %time%
pause&goto :eof
需时

  Quote:
23:23:50.00
23:23:50.37


@echo off
:loop
set time_=%time%
if not %time_:~-4% == 0.00 goto loop
for /f "tokens=1,2" %%i in (1.txt) do echo %%i %%j
echo %time_%
echo %time%
pause&goto :eof
需时

  Quote:
23:24:10.00
23:24:10.01



   此帖被 +4 点积分        点击查看详情   
评分人:【 bat-zw 分数: +4  时间:2008-4-3 00:47




2008-4-3 00:38
查看资料  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 5 楼』:  明白了,谢谢:

又学了新东西,真是学海无涯啊!



批处理之家新域名:www.bathome.net
2008-4-3 00:46
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复
xtanbmy
初级用户




积分 47
发帖 31
注册 2008-3-17
状态 离线
『第 6 楼』:  

很好的,学习了。

2008-4-7 19:42
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: