Board logo

标题: 关于去最大值去最小值,中间值求平均数的脚本 [打印本页]

作者: maya0su     时间: 2006-5-24 13:26    标题: 关于去最大值去最小值,中间值求平均数的脚本

如题:
比如有一组数值,是否可以用批处理或者VBS脚本,去除其中的最大最小值,然后其余的数值求平均值?
作者: 3742668     时间: 2006-5-25 21:28
当然可以,如果用JS的话,它带有一个排序函数:sort,用来解决是很简单的,如果用VBS,也有多种方法,最理想的莫过于利用创建断开的数据集对象来操作,可以像操作数据库一样来编辑那些数据,还能保存为各种格式的文件,不过,在中国DOS联盟,我还是给你个命令行下的批处理版吧:
@echo off
set Count=10                       rem 参加计算的数的个数
call :GetNum %Count%          rem 产生随机数
echo 要处理的数据为:%Num%
call :EditNum %Num%
pause
exit

:EditNum
    set /a intMax=1,intMin=2147483647      rem 批处理最大只能处理32位数据
    setlocal enabledelayedexpansion
    for %%i in (%*) do (if %%i GEQ !intMax! set /a intMax=%%i) & (if %%i LEQ !intMin! set /a intMin=%%i)
    for %%j in (%*) do set /a intCount=!intCount! + 1
    echo 有%intCount%个数,其中最大和最小分别为%intMax%,%intMin%
    set total=%Num: =+%
    set /a total=%total%
    set /a total=(%total% - %intMax% - %intMin%) / (%intCount% - 2)
    echo 总数为:%total%
goto end

:GetNum
    if "%Flag%" == "%1" goto end
    set Num=%Num% %Random%
    set /a Flag = %Flag% + 1
goto GetNum

:end
    endlocal
    set Flag=
    set intMax=
    set intMin=
    set intCount=
    set total=

作者: willsort     时间: 2006-5-25 22:57
Re 3742668:

      很不错的方案。

      只是似乎intMax的初值似应取-2147483648,或者intMax和intMin都取%1初值也是可以的。

      另外,:EditNum使用了全局变量%Num%,虽然这是一个很巧妙的技巧,但它不符合局部模块不应访问全局变量的习惯,通用性被降低了,通常我们是在判断最小值和最大值的循环中求得变量和的,同时可以进行一些溢出错误处理。
作者: 3742668     时间: 2006-5-25 23:14
对于intMax的初值开始是考虑过,不过考虑到%random%只能产生1-32767之间的数,所以就选择的是1,至于intMin用2147483647是因为觉得32767的范围似乎太小了一点,再说正整数的比较是比较常见的。
    至于访问%Num%全局变量的问题,如果是用VBS或者其他的话,可能不会出现这种情况,只不过实在懒得去多写一个for来从%*获得算式,因为我认为在批处理中并不存在什么局部变量,统统都是全局变量。
作者: willsort     时间: 2006-5-25 23:24
Re 3742668:

      你的代码不应该只能适应你的测试数据,我们无法假定测试数据必然是正整数,所以初值的修改还是必要的。

      2147483647是个与环境相关的数,我们在设计算法时应避免使用,否则如果在64位的系统中可能会出现问题。

      批处理中是存在局部变量的,至少在CMD中,我们可以使用setlocal来限定变量的作用域和生存周期。

      如果将你的:EditNum移植到其他程序中或者直接调用它,则很可能出现问题。

      求和和求个数可以在判断最小值和最大值的for循环一体实现,并不很麻烦。

[ Last edited by willsort on 2006-5-25 at 23:27 ]
作者: maya0su     时间: 2006-6-2 22:54
我的意思是,能不能打开后,程序等待输入数字,这些数字可能是N个,然后去大去小,最后的求平均值!
作者: willsort     时间: 2006-6-3 19:33
Re maya0su:

      有了 3742668 兄的代码在前,编写等待输入求平均数的代码应该不是很难,根据你的要求作了相应的修改。
:: Average.cmd - Eval average of a batch of numbers
:: Will Sort - 2006-06-03 - CMD@WinXP
@echo off
call :GetNum
echo 要处理的数据为:%return%
call :Average %return%
echo 去除最大值和最小值的平均数为 %return%
goto :eof

:GetNum
if "%_n%"=="" setlocal
set _n=-
set /p _n=请输入一个整数(直接回车结束输入):
if "%_n%"=="-" endlocal&set return=%return%&goto :eof
set /a _i=_n
if "%_i%" NEQ "%_n%" (echo 无效的输入数据:%_n%
) else set return=%return% %_i%
goto GetNum

:Average
setlocal EnableDelayedExpansion
if "%3"=="" set return=N/A&goto :eof
set /a iMax=%1,iMin=%1
for %%i in (%*) do (   
    if %%i GTR !iMax! set /a iMax=%%i
    if %%i LSS !iMin! set /a iMin=%%i
    set /a iTotal+=%%i
    set /a iCount+=1
)
set /a return=(iTotal-iMax-iMin) / (iCount-2)
endlocal&set return=%return%&goto :eof

作者: maya0su     时间: 2006-7-24 14:09
又有一个新的问题出现了
我想利用另一个批处理调用此程序,从而实现循环
@echo off
:loop
cls
call itbat.bat


set /p start=是否继续?(是Y 否N)
if "%start%"=="y" goto :loop
if "%start%"=="n" goto :end

:end
exit

在实现循环的过程出现了一个现象就是
上次计算后的结果,也就是那个平均值会出现下一次的输入数中
同时也参与下一次的运算!
请问有办法解决吗?

[ Last edited by maya0su on 2006-7-24 at 14:11 ]
作者: namejm     时间: 2006-7-24 17:25
  问题出在call :Average %return%这一句。如果在循环调用的时候能清空%return%的值就好办了。
作者: zh159     时间: 2006-7-24 18:30
直接在“call itbat.bat”后加入“set return=”不就行了么
作者: namejm     时间: 2006-7-24 22:09
  呵呵,楼上的,我也曾有过这样的冲动,可是,你试验过了吗?发言要慎重哦。
作者: zh159     时间: 2006-7-25 00:39


  Quote:
Originally posted by namejm at 2006-7-24 22:09:
  呵呵,楼上的,我也曾有过这样的冲动,可是,你试验过了吗?发言要慎重哦。

改一下willsort版主的:

  Quote:
:: Average.cmd - Eval average of a batch of numbers
:: Will Sort - 2006-06-03 - CMD@WinXP
@echo off
set return=
call :GetNum
echo 要处理的数据为:%return%
call :Average %return%
echo 去除最大值和最小值的平均数为 %return%
goto :eof

:GetNum
if "%_n%"=="" setlocal
set _n=-
set /p _n=请输入一个整数(直接回车结束输入):
if "%_n%"=="-" endlocal&set return=%return%&goto :eof
set /a _i=_n
if "%_i%" NEQ "%_n%" (echo 无效的输入数据:%_n%
) else set return=%return% %_i%
goto GetNum

:Average
setlocal EnableDelayedExpansion
if "%3"=="" set return=N/A&goto :eof
set /a iMax=%1,iMin=%1
for %%i in (%*) do (   
    if %%i GTR !iMax! set /a iMax=%%i
    if %%i LSS !iMin! set /a iMin=%%i
    set /a iTotal+=%%i
    set /a iCount+=1
)
set /a return=(iTotal-iMax-iMin) / (iCount-2)
endlocal&set return=%return%&goto :eof
set return=

OK

或者maya0su的:

  Quote:
@echo off
:loop
cls
set return=
call itbat.bat
set return=


set /p start=是否继续?(是Y 否N)
if "%start%"=="y" goto :loop
if "%start%"=="n" goto :end

:end
exit

也OK

[ Last edited by zxcv on 2006-7-25 at 00:41 ]
作者: namejm     时间: 2006-7-25 12:50
  原来是要加两处,zxcv的代码不错。看来自己得对 call 标号 参数 的格式多加揣摩才是。