Board logo

标题: 【练习-015】批处理随机取值练习 [打印本页]

作者: batman    时间: 2008-8-25 09:39     标题: 【练习-015】批处理随机取值练习

出题目的:
        掌握利用random进行随机取值技巧
解题要求:
        代码通用、高效
        尽量简洁
        尽量不生成临时文件
加分规则:
        1 思路独特基准分5分
        2 代码高效、通用基准分4分
        3 技巧高超基准分3分
        4 代码简洁基准分2分
        5 完美代码加分15分
题目如下:
  已知有1-26与a-z的一一对应,如1对应a 10对应j 26对应z,要求用批处理
从1-26 a-z这52个值中(全视为值)随机抽取10个互不相同的值并显示出来,
注意如同1和a 24和x 26和z这样的取值均视为相同不合要求。      
解题限制:
        暂无限制。
------------------------------------------------------------------------------------------------
目前的最佳答案见:16楼本人的解

[ 本帖最后由 batman 于 2008-8-30 13:10 编辑 ]
作者: wangwei4106    时间: 2008-8-25 09:46

呵呵
你昨天不是做好了吗?
我这还有你写的代码。
作者: 523066680    时间: 2008-8-25 10:28

这是题目 给大家锻炼的。并不是有了一种方法 就不用做题了
作者: more    时间: 2008-8-25 13:04

哈哈,恭喜if exist成为技术组成员了!!!
废话就不多说了,不知是不是这样?
  1. @echo off
  2. Setlocal Enabledelayedexpansion
  3. set "var1=a b c d e f g h i j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z"
  4. for /l %%a in (1 1 26) do (set "var2=!var2!%%a ")
  5. for %%a in (%var1%) do (set /a "nn+=1"&set "!nn!=%%a"&set "%%a=!nn!")
  6. echo %var1%&echo %var2%&echo.
  7. :lp
  8. set /a "bt=%random%%%26+1","aa=%random%%%2+1"
  9. for /f "tokens=%bt%" %%a in ("!var%aa%!") do (
  10.    if defined .%%a goto :lp
  11.    if defined .!%%a! goto :lp
  12.    set "ech=!ech! %%a"
  13.    set ".%%a=ok"&set ".!%%a!=ok"
  14. )
  15. set /a mm+=1
  16. if %mm% lss 10 goto :lp
  17. echo %ech%
  18. for %%a in (%var1%) do (set ".%%a="&set ".!%%a!=")
  19. set "mm=0"&set "ech="
  20. pause>nul&goto :lp
复制代码

作者: batman    时间: 2008-8-25 14:11

楼上的代码写得复杂且效率低,但答案还是对的,加分鼓励。
作者: pusofalse    时间: 2008-8-25 14:26

  1. @echo off&setlocal enabledelayedexpansion
  2. for %%i in (a b c d e f g h i j k l n m o p q r s t u v w x y z) do set "letter=!letter! %%i"
  3. for /l %%a in (1 1 26) do set "num=!num! %%a"
  4. :loop
  5. set/a n=%random%%%26+1
  6. if defined .%n% goto loop
  7. set .%n%=a
  8. if defined a (set var=%letter%) else set var=%num%
  9. for /f "tokens=%n%" %%a in ("%var%") do set/p=%%a <nul
  10. if not defined a (set a=a) else set "a="
  11. set/a m+=1
  12. if %m% neq 10 goto loop
  13. pause>nul
复制代码

等看BATMAN兄的代码。

[ 本帖最后由 pusofalse 于 2008-8-25 14:34 编辑 ]
作者: batman    时间: 2008-8-25 15:02

&&pusofalse版主代码已经比较完美了,就是在效率上还存在一点小问题,其实对于这种
随机取值的问题在取值基数和取值个数差值较大时(如从1-100中随机取10个不同的数)
使用if判断返回还是可以的,但一旦取值基数和取值个数差值小甚至为0时(如从1-100中
随机取100个不同的数)这种方法就解决不了问题了,所以对于此类问题个人建议使用乱序
来进行处理,下面就以从1-100中随机取100个不同的数为例给出代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%i in (1,1,100) do set "_!random!!random!!random!!random!=%%i"
  3. for /f "tokens=2 delims==" %%i in ('set _') do set /p=%%i <nul
  4. pause>nul
复制代码

作者: more    时间: 2008-8-25 15:08

将4楼及6楼的代码改一下,貌似4楼的效率要比6楼的高些喔.
必须要承认的是6楼的想法比我的好多了,呵呵...
但是用时却比我的多,不知为何...
4楼:
  1. @echo off
  2. Setlocal Enabledelayedexpansion
  3. set "var1=a b c d e f g h i j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z"
  4. for /l %%a in (1 1 26) do (set "var2=!var2!%%a ")
  5. for %%a in (%var1%) do (set /a "nn+=1"&set "!nn!=%%a"&set "%%a=!nn!")
  6. Rem echo %var1%&echo %var2%&echo.
  7. :lp1
  8. echo %time%
  9. :lp
  10. set /a "bt=%random%%%26+1","aa=%random%%%2+1"
  11. for /f "tokens=%bt%" %%a in ("!var%aa%!") do (
  12.    if defined .%%a goto :lp
  13.    if defined .!%%a! goto :lp
  14.    set "ech=!ech! %%a"
  15.    set ".%%a=ok"&set ".!%%a!=ok"
  16. )
  17. set /a mm+=1
  18. if %mm% lss 10 goto :lp
  19. for %%a in (%var1%) do (set ".%%a="&set ".!%%a!=")
  20. set "mm=0"
  21. echo %ech%&echo %time%
  22. set "ech="
  23. pause>nul&cls&goto :lp1
复制代码
6楼:
  1. @echo off&setlocal enabledelayedexpansion
  2. for %%i in (a b c d e f g h i j k l n m o p q r s t u v w x y z) do set "letter=!letter! %%i"
  3. for /l %%a in (1 1 26) do set "num=!num! %%a"
  4. :lp
  5. echo %time%
  6. :loop
  7. set/a n=%random%%%26+1
  8. if defined .%n% goto loop
  9. set .%n%=a
  10. if defined a (set var=%letter%) else set var=%num%
  11. for /f "tokens=%n%" %%a in ("%var%") do set "wow=!wow! %%a"
  12. if not defined a (set a=a) else set "a="
  13. set/a m+=1
  14. if %m% neq 10 goto loop
  15. for /l %%a in (1 1 26) do (set ".%%a=")
  16. set "m=0"
  17. echo %wow%&echo %time%
  18. set "wow="
  19. pause>nul&cls&goto :lp
复制代码

作者: pusofalse    时间: 2008-8-25 15:33

兄的学习态度太好了。
测试了一下,兄的代码平均间隔在0.02秒之内,我的代码差不多是0.03s。
的确慢了,可能是用了if defined 的缘故

[ 本帖最后由 pusofalse 于 2008-8-25 15:34 编辑 ]
作者: 523066680    时间: 2008-8-25 15:34

各位也都发表啦,我的也放出来啦 偶的还是原来的样子
  1. @echo off&setlocal enabledelayedexpansion
  2. set /a a=0,act=0
  3. for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do  (
  4. set /a a+=1
  5. set n!a!=%%a)
  6. :act
  7. set /a act+=1
  8. :act-1
  9.   set /a n=%random%%%27
  10.   if %n% equ 0 set n=1
  11.   if not defined _%n% (
  12.       if %random:~-1% lss 5 (set number%act%=%n%) else (set number%act%=!n%n%!)
  13.       set _%n%=exist
  14.   ) else (goto :act-1)
  15.   echo !number%act%!
  16. if %act% lss 10 goto :act
  17. pause
复制代码
再小小修改代码,测试获得字母Z的频数,用来测试前面的代码随机性是否良好
  1. @echo off&setlocal enabledelayedexpansion
  2. set /a a=0,act=0
  3. for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do  (
  4. set /a a+=1
  5. set n!a!=%%a)
  6. set test=0
  7. :act
  8. set /a act+=1
  9.   set /a n=%random%%%27
  10.   if %n% equ 0 set n=1
  11.       if %random:~-1% lss 5 (set number%act%=%n%) else (set number%act%=!n%n%!)
  12.   if !number%act%! equ z (set /a test+=1)
  13. if %act% lss 520 goto :act
  14. echo,520次 有%test%次出现z
  15. pause
复制代码





----------------
本楼第一段代码出现概率不平衡问题,请参照11楼和13楼的说法

[ 本帖最后由 523066680 于 2008-8-25 20:58 编辑 ]
作者: more    时间: 2008-8-25 15:44

其实10楼的这部分代码可以这样写的
  1. set /a n=%random%%%27
  2. if %n% equ 0 set n=1
复制代码
  1. set /a n=%random%%%26+1
复制代码

作者: batman    时间: 2008-8-25 16:10

原帖由 523066680 于 2008-8-25 15:34 发表
各位也都发表啦,我的也放出来啦 偶的还是原来的样子@echo off&setlocal enabledelayedexpansion
set /a a=0,act=0
for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do  (
set /a a+=1
set  ...

必须要指出你的问题了:
  代码书写极不规范,基本忽略了代码的可阅读性和美观性,在充分发挥兄弟的特长的基础上还请在这方面多下点功夫。。。
作者: itrui    时间: 2008-8-25 17:53

原帖由 more 于 2008-8-25 15:44 发表
其实10楼的这部分代码可以这样写的set /a n=%random%%%27
if %n% equ 0 set n=1set /a n=%random%%%26+1


我觉得不是可以那样写,而是应该那样写,否则出现1的概率比其他数都大了1倍。随机应该要求概率一样。
作者: 523066680    时间: 2008-8-25 20:55

原帖由 itrui 于 2008-8-25 17:53 发表


我觉得不是可以那样写,而是应该那样写,否则出现1的概率比其他数都大了1倍。随机应该要求概率一样。


啊 这位真够细心啊!谢谢各位的指教!我会好好努力的!
作者: pusofalse    时间: 2008-8-25 22:14

你说的,随机的概率应该相等。
那么你写为if %n% equ 0 set n=1
出现1的概率也会比其他数多一倍。
我觉得没有绝对的概率相等,底数的概率总会多于其他数。
作者: batman    时间: 2008-8-26 12:09     标题: 下面给出本人的解:

  1. @echo off&setlocal enabledelayedexpansion
  2. for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
  3.      set /a n+=1,a=!random!%%2
  4.      if !a! equ 0 (
  5.         set "_!random!!random!!random!=%%i"
  6.         ) else (
  7.         set "_!random!!random!!random!=!n!"
  8.      )
  9. )
  10. for /f "tokens=2 delims==" %%i in ('set _') do (
  11.      set /a n-=1
  12.      if !n! equ 15 pause>nul&goto :eof
  13.      set /p=%%i <nul
  14. )
复制代码

[ 本帖最后由 batman 于 2008-8-26 12:13 编辑 ]
作者: mkl    时间: 2008-8-27 20:15

  1. @echo off&setlocal enabledelayedexpansion
  2. :jj
  3. set aa=1
  4. for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
  5. set !aa!=%%i &set /a aa=!aa!+1
  6. )
  7. set va=1
  8. :tj
  9. set /a dd=%random%%%26+1 &set/a ss=%random%%%2
  10. if %ss%==0 (set/p=%dd% <nul) else set/p=!%dd%! <nul
  11. set/a va+=1
  12. if %va% lss 11 goto tj
  13. pause>nul
复制代码

作者: batman    时间: 2008-8-27 20:23

楼上没考虑重复的情况?
作者: mkl    时间: 2008-8-28 21:02

考虑后如下,但效率低
  1. @echo off&setlocal enabledelayedexpansion
  2. :jj
  3. set aa=1 &set "bb="
  4. for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
  5. set !aa!=%%i &set /a aa=!aa!+1
  6. )
  7. set va=1
  8. :tj
  9. set /a dd=%random%%%26+1 &set/a ss=%random%%%2
  10. echo %bb% |find "%dd: =%">nul 2>nul &&goto tj
  11. set bb=%bb% %dd%
  12. if %ss%==1 (set/p=%dd% <nul) else set/p=!%dd%! <nul
  13. set/a va+=1
  14. if %va% lss 11 goto tj
  15. pause>nul
复制代码

作者: mkl    时间: 2008-8-28 21:20

原帖由 batman 于 2008/8/26 12:09 发表
@echo off&setlocal enabledelayedexpansion
for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
     set /a n+=1,a=!random!%%2
     if !a! equ 0 (
        set "_!random!!random!!ra ...

请问 set_ 是什么意思?还有那个 set "_!random!!random!!random!=%%i 呢?
作者: batman    时间: 2008-8-29 00:51

原帖由 mkl 于 2008-8-28 21:20 发表

请问 set_ 是什么意思?还有那个 set "_!random!!random!!random!=%%i 呢?

请在我的代码的第一个for循环后加入一个set _运行看看,其实set _就是显示所有以_字符
打头的变量,具体可在cmd中键入set /?查询。
作者: 随风    时间: 2008-8-30 18:32

16楼 方法确实巧妙,不错。。!
作者: netbenton    时间: 2009-5-2 17:25     标题: 来一个规规矩矩的

取到一个剔除一个
  1. @echo off&setlocal enabledelayedexpansion
  2. set "str=a b c d e f g h i j k l m n o p q r s t u v w x y z "
  3. for %%i in (%str%) do (set/a #+=1,%%i=#)
  4. for /l %%a in (1,1,10) do (
  5.     set/a asc=!random!%%#*2,#-=1
  6.     for %%b in (!asc!) do (set asc=!str:~%%b,1!)
  7.     for %%b in (!asc!) do (set str=!str:%%b =!&set/a $=!random!%%2,1/$ 2>nul||set asc=!%%b!)
  8.     echo !asc!
  9. )
  10. pause
复制代码

作者: batman    时间: 2009-5-2 20:01

楼上会存在效率问题,特别是用到了||管道符。

[ 本帖最后由 batman 于 2009-5-2 20:03 编辑 ]
作者: netbenton    时间: 2009-5-2 23:31

测试了一下,“||”管道操作虽然要比其它管道操作快,但是比起if还是要慢好多,相当于if 用时的5~8倍。
改为用if 判断。综合测度速度不错。
  1. @echo off&setlocal enabledelayedexpansion
  2. set "str=a b c d e f g h i j k l m n o p q r s t u v w x y z "
  3. for %%i in (%str%) do (set/a #+=1,%%i=#)
  4. for /l %%a in (1,1,10) do (
  5.     set/a asc=!random!%%#*2,#-=1
  6.     for %%b in (!asc!) do (set asc=!str:~%%b,1!)
  7.     for %%b in (!asc!) do (set str=!str:%%b =!&set/a $=!random!%%2&if !$! equ 0 set asc=!asc!)
  8.     echo !asc!
  9. )
  10. pause
复制代码

作者: zhouyongjun    时间: 2009-6-16 23:15

  1. @echo off&setlocal enabledelayedexpansion
  2. set "str=a b c d e f g h i j k l m n o p q r s t u v w x y z"
  3. for %%i in (%str%) do set/a n+=1&set "_!n!=!n! %%i"
  4. :loop
  5. set/a m=%random%%%26+1,n=%random%%%2+1
  6. if not defined #%m% (
  7.     for /f "tokens=1,2" %%1 in ("!_%m%!") do (
  8.         <nul set/p=%%%n% &set/a num+=1,#%m%=0
  9.      )
  10. )
  11. if %num% lss 10 goto loop
  12. echo/&pause
复制代码





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