Board logo

标题: [数值计算] [讨论]批处理按数字大小排序 [打印本页]

作者: youxi01    时间: 2007-11-8 18:33     标题: [讨论]批处理按数字大小排序

本帖最后由 pcl_test 于 2016-11-3 20:22 编辑

有以下几个数字(注:批处理中,数字超出2^31会自动当成字符串,如:set /a num=99999999999999就会出错)
包括特大数字,现需要对它们进行排序(由小到大)。如何处理?

数字有:
  1. 123
  2. 65
  3. 9999999999999
  4. 11111111111111
  5. 44444456
  6. 879554213
  7. 658974452136541
复制代码

作者: namejm    时间: 2007-11-8 21:09

  排序一般要用到sort,不过,sort是逐位做比较,比如sort认为12大于100,因为第二位上,2大于0。要避免这样的情况,可以考虑只对同一长度的数字串做比较。例如以下代码就可以成功解决逐位比较和超大数带来的问题,只不过效率比较低下:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. :: 统计数字串的最大长度
  4. set max=0
  5. for /f %%i in (test.txt) do (
  6.     set length=0
  7.     call :CheckLength %%i
  8.     if !length! geq !max! set max=!length!
  9. )
  10. :: 在文本最后插入空行,消除findstr整行匹配时忽略最后一行带来的影响
  11. echo.>>test.txt
  12. :: 对同一长度的数字串做比较
  13. for /l %%i in (1,1,%max%) do (
  14.     set str=!str![0-9]
  15.     for /f %%j in ('findstr /be "!str!" test.txt^|sort') do echo %%j
  16. )
  17. pause
  18. exit
  19. :CheckLength
  20. set str=%1
  21. :loop
  22. set /a length+=1
  23. set str=!str:~1!
  24. if defined str goto loop
  25. goto :eof
复制代码

作者: 随风    时间: 2007-11-8 22:20

对于findstr的表达式一直是晕晕的,对sort的用法也一直是晕晕的,
既然说sort可以对相同位数的数进行排序,且可以处理超大数,
那么用补零的办法似乎也可以,那样就可以不用findstr命令.
namejm 说的效率低,不知是因为用了findstr的原因么?
而且我用你的代码处理一个超大数时,222222222222222222222222222222222 findstr居然报错!!
不知道是我的findstr命令有问题,还是本就如此.
用补零的方法,感觉快些.
::
  1. @echo off&setlocal enabledelayedexpansion
  2. if not "%1"==":" (
  3.   for /f %%a in ('"%~0" :^|sort') do (
  4.   for /f "tokens=1,2 delims=0" %%b in ("%%a") do (
  5.   set num=%%b
  6.   if "%%b"=="a" (echo 0) else echo !num:~0,-1!
  7.   ))
  8.   pause&exit
  9. )
  10. :: 统计数字串的最大长度
  11. set max=100
  12. for /f %%i in (a.txt) do (
  13.   set length=100
  14.   call :CheckLength %%i
  15.   if !length! geq !max! set max=!length!
  16.   )
  17.   for /l %%a in (1 1 %max%) do set num=0!num!
  18.   for /f %%i in (a.txt) do (
  19.   set var=!num!%%i
  20.   call echo %%var:~-!max!%%a
  21. )
  22. goto :eof
  23. :CheckLength
  24.   set str=%1
  25.   if "%str:~100,1%"=="" (goto :eof) else set str=!str:~100!
  26. :loop
  27.   set /a length+=1
  28.   set str=!str:~1!
  29.   if defined str goto loop
  30. goto :eof
复制代码

[ 本帖最后由 随风 于 2007-11-9 20:11 编辑 ]
作者: youxi01    时间: 2007-11-8 22:23

2F的能满足要求,但是似乎效率确实不高...
个人 觉得 没必要 使用findstr,终究那个会影响效率。
可以采用的方法(思路):
获取位数,然后和该数字排在一起
举例,对于以下数字(10位以内):
9
85
765
6542
56987
可以这样处理:
1 9
2 85
3 765
4 6542
5 56987
然后再排,这样效率会提高很多...
当然,位数超过10的类同
作者: youxi01    时间: 2007-11-8 22:31

3F的代码不错,效率比较高啊
作者: youxi01    时间: 2007-11-8 22:36

3F补0的方法 比我的 4F提出来的 取位数 再“合成”的设想要好啊,赞一个,加分
作者: namejm    时间: 2007-11-8 23:03

  4楼获取数字串长度值并和数字串并排的方法,实际上是很难实现的,因为sort并不能分离出同一长度的数字串;就算是分离出来了,还会生成临时文件;综合起来考虑的话,效率应该还没有2楼的高。

  3楼补零的方法效率大为提升,并且不会导致产生findstr的错误,应该是这个问题的完美解决方案。顺便提醒一下,%~0 最好写成 "%~0" ,以避免特殊路径带来的影响。通过测试,用2楼的代码处理超过15位的数字就会产生错误,但是,单用findstr来搜索超过15位的数字时,并没有任何问题,可能是 findstr.exe 设计上的bug。
作者: xiaoxx    时间: 2008-4-28 18:42

没看懂程序的执行顺序
for /f %%a in ('"%~0" :^|sort')有什么作用
作者: 随风    时间: 2008-4-28 20:13

if not "%1"==":" (
  for /f %%a in ('"%~0" :^|sort') do (
意识是,当%1不等于:冒号的时候,就运行这句,也就是第一次运行的时候,因为%1是空,也就是不等于:冒号,  %~0代表自身 后面的:是给它的参数,就是再次运行自身,并给%1赋值为:冒号.当%1等于冒号时就运行下面的语句.运行完后,返回到%~0处,再把结果交给sort排序,最后输出..
作者: xiaoxx    时间: 2008-4-28 21:25

明白了 感谢




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2