[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

【练习-059】批处理解实现自动新生分班

出题目的:
    让大家熟练掌握随机数概念和用法
解题要求:
    1、代码简洁、高效、通用并不生成临时文件
    2、请版主级会员暂缓解题,但可跟贴为新人做指导
加分规则:
    本题满分15分,视情况加分
题目如下:
    某学校要新招收400名学生,其中有100名优等生、100名高等生、100名中等生、100名差等生,现在学校校长要求将这400名
学生随机安排到新开的10个班,同时要求每个班有10名优等生、10名高等生、10名中等生、10名差等生,并且要在学生报到的时候
就分好班次,并且他要为两个学生开后门,一个是将教育局局长的儿子分到第3班,一个是将文化局局长的女儿分到第8班。这下可
难坏了招生办的老师,一时都不知道怎么办,正好这时教务处长来了,他马上想到一个好办法,终于招生办解决了校长交给的难题,
受到校长的表扬。现在假设你是教务处长,你能想到什么好办法吗?请注意,我不是要你们写文字,要看你们的代码,请最后将每个
班的学生显示出来(最好是分屏显示)
随题提示:
    1、优等生用A-1至A-100表示,高等生用B-1至B-100表示,中等生用C-1至C-100表示,差等生用D-1至D-100表示
    2、教育局局长的儿子用B-60表示,文化局局长的女儿用C-49表示
    3、班级用X-1至X-10表示
    4、假设学生报到的顺序不是随机的,是按A-D、1-100的顺序来进行,即先按1-00的顺序招收优等生,再按1-100的顺序招收高等
生,依此类推直到招收D-100,所以才要求在报到时就随机分好班

要睡觉了,看来本题确实有难度,先给出本人的参考答案吧,不过大家还是争取不要看答案哦:


  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in (A B C D) do (
  3.     for /l %%b in (1,1,100) do set ".!random!_%%a-%%b=%%a-%%b"
  4.     for /f "tokens=2 delims==" %%b in ('set .') do (
  5.         if not defined code set "code=123456789a"&set /a n=10
  6.         set /a a=!random!%%n
  7.         for %%c in (!a!) do (
  8.             set "a=!code:~%%c,1!"
  9.             for %%c in (!a!) do (
  10.                 set "code=!code:%%c=!"&set "X-%%c=!X-%%c! %%b"&set /a n-=1
  11.                 for %%d in (B-3 C-8) do (
  12.                     for /f "tokens=1,2 delims=-" %%e in ("%%d") do (
  13.                         if %%e equ %%a if %%f equ %%c if not defined _%%e%%f set "_%%e%%f=%%b"
  14.                     )
  15.                 )
  16.                 for %%d in (B-60 C-49) do if "%%d" equ "%%b" set ".%%d=X-%%c"
  17.             )  
  18.         )
  19.     )
  20.     for /f "delims==" %%b in ('set .') do set "%%b="
  21. )
  22. set "X-10=%X-a%"
  23. if "%X-3:B-60=%" equ "%X-3%" set "X-3=!X-3:%_B3%=B-60!"&call,set "!.B-60!=%%!.B-60:B-60=%_B3%!%%"
  24. if "%X-8:C-49=%" equ "%X-8%" set "X-8=!X-8:%_C8%=C-49!"&call,set "!.C-49!=%%!.C-49:C-40=%_C8%!%%"
  25. for /l %%a in (1,1,10) do cls&echo X-%%a班:&echo.&echo !X-%%a:~1!&pause>nul
复制代码

-------------------------------------------------------------------------------------------------------------------------------------------
此代码重复随机,不可取,请大家看后面的代码。

[ 本帖最后由 batman 于 2010-6-29 09:22 编辑 ]
***共同提高***

那就不是易读性的问题,而是技巧性的问题。
我说过,需要相当的基础和积累才行。

set的这个用法你不会,说明你的基本功还不够,对常用命令都不熟。
set /?
    SET P
会显示所有以字母 P 打头的变量

而set /a进行数学运算时,“您可以使用环境变量值做计算而不用键入那些 % 符号来得到它们的值”
据此分析set /a n=!random!%%_%%a*4
断句一下就是set /a n = !random! %% _%%a * 4
前面的%%是求余运算符(在bat中要写成两个,预处理机制,原理和理论知识),!random!加了!符号,因为它是一个特殊的变量,不是我们手动定义的,而是系统提供的动态环境变量,所以要使用!!来得到其值。而_%%a就是的!_%%a!省去!的形式,只是这个展开过程稍微多一步:先由for展开%%a的值,与_拼接后整个成为一个变量名,再由set得到该变量对应的值。
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

看的就是技巧啦,为什么你写的出来,我写不出来。为什么你的代码效率高而我的慢的要死。为什么你的代码那么短而且不生成临时文件,而我就不行。就是看你们的代码去找出这些问题,学习你们的思路和技巧
就拿一个不生成临时文件的方法来说:set
在我开始学批处理,看教程的时候,我对于set的关注和主观想法认为他的作用是设置变量,忽略了他的另一个功能显示变量。所以在做练习题的时候,我就搞不懂为什么可以这样用。寒夜孤星教过我,然后慢慢掌握了这个用法
在拿这个题来说,刚开始我不知道怎么着手,当时我的想法是如何取10个不同的随机数来取出这些数,我看了一下随风的代码发现了set #%%a-!random!-%%a-%%b=0的巧妙用法,然后一下困扰我的难题就解开了,同时也做出了这个题,虽然效率不高。但是也做出来了
努力学习,努力挣分

TOP

回复 39楼 的帖子

看36楼的代码,你觉得哪里头疼呢?

代码功能和技巧原理可能不大懂,需要相当的基础和积累才行。但代码格式、基本结构应该容易看懂吧(少数风格迥异的牛人除外,只看三两遍和没看一样)
比如一行句子是什么结构、怎么断句、主体命令是什么,for循环是哪一种、循环体里面有哪些子句,if语句的条件分支是怎样的,从哪里到哪里、是什么逻辑关系;总之大体框架应该读能出来。

试比较35楼的
set /a n=!random!%%_%%a*4
和36楼的
set /a ran = !random! %% left + 1

新手对上面那句,可能很难明白(当然结合代码是必须的,可是对新手还是很难);但下面那句就不一样了(当然本身就简单一点)
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

赞同,至少要有缩进。
每次看到全部顶格的代码,总有一种想打人的冲动。
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

易读这点有待商量,因为你们写的好多代码对于我们这类初学者来说,看起来头疼
努力学习,努力挣分

TOP

为什么大家都觉得我是计算机专业的呢?

编程规范要求一行上最好只放一条语句(其实大家都懂的)

set /a 后面加空格是可以的而且是应该的,以突出运算逻辑和提高可读性。它和set进行字符串赋值有所不同,对于后者多余的空格也会成为变量名/值的一部分。

变量命名应该尽量做到短小而又有所含义(能做到见名知义就更好了),不要全用毫无意义的a、b、c之类的,当然有一些习惯性用法,比如n表示数量,i用于for循环变量等。

语句对齐问题:我发现做到并坚持这一原则的人真的很少。批处理就算再简单,基本的结构还是有的,不要一味为了简洁就无视它。
复合语句收尾的括号应与关键字在同一列上对齐(主要就是if、for,因为开始的括号不能另起一行放在行首,否则就与它对齐了),内部子语句应该适量缩进(一般4个空格,多数编辑器都是这个默认值,不用你多敲)。当子语句只有一两个且较简单,也可以省去括号(在bat中不反对大家这么做)。

正确、高效、易读,最容易做到的就是易读,却往往最难被人做到,悲乎哀哉!就算代码功能上不怎么样,变量名称、基本意思、流程结构应该写清楚呀,起码能让人看得懂。(terse的代码一向高效,但我一般都没怎么看过,感觉太“难看”了^_^)
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

回复 36楼 的帖子

听你说正在学习编程规范, 一点好奇: 难道你不是计算机专业的(当然你可以不答我)
你这帖的代码, 我没大细看, 但 发现 echo off 和 setlocal 没用 & 放在同一行了,
set /a 后面的运算符也都前后都空出一个空格了.
这点上我提一个题外话, 至少我在做一些代码时自己犯了一个狭念:
把代码做浮华性的 "简化", 甚时在变量名上做不必要的简化, 略到只用一个字母.

什么样的代码才是好的? 正确, 高效, 易读, 而所谓 "简洁", 应是代码具备了实质上内在的品质而自然表现出的外在品质.

TOP

  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set amount=100
  4. set types=A B C D
  5. set slices=10
  6. set special=B-60-3 C-49-8
  7. for /l %%a in (1 1 %amount%) do set arr=!arr! #-%%a
  8. for %%i in (%types%) do (
  9.     set "%%i=!arr:#=%%i! " 后面特意加了空格
  10.     set /a amount_%%i=amount
  11.     for /l %%a in (1 1 %slices%) do set /a num_%%i_%%a = amount / slices
  12. )
  13. for %%a in (%special%) do (
  14.     for /f "tokens=1,2,3 delims=-" %%i in ("%%a") do (
  15.         set %%i=!%%i: %%i-%%j = !
  16.         set /a amount_%%i -= 1
  17.         set /a num_%%i_%%k -= 1
  18.     )
  19. )
  20. for %%i in (%types%) do (
  21.     set #=!%%i!
  22.     set /a left = amount_%%i
  23.     for /l %%a in (1 1 %slices%) do (
  24.         for /l %%n in (1 1 !num_%%i_%%a!) do (
  25.             set /a ran = !random! %% left + 1
  26.             set $=!#!
  27.             for /l %%x in (1 1 !ran!) do set $=!$:* =!
  28.             for /f %%x in ("!$!") do set item=%%x
  29.             set slices_%%a=!slices_%%a! !item!
  30.             for %%x in (!item!) do set #=!#: %%x = !
  31.             set /a left -= 1
  32.         )
  33.     )
  34. )
  35. for %%a in (%special%) do (
  36.     for /f "tokens=1,2,3 delims=-" %%i in ("%%a") do set slices_%%k=!slices_%%k! %%i-%%j
  37. )
  38. for /l %%a in (1 1 %slices%) do echo class %%a:& echo !slices_%%a!& echo;
  39. echo;
  40. pause
  41. exit /b
  42. :shuffle arrName len cnt //洗牌
复制代码
适应每个数组元素名字未知(开始生成一个数组是当没有给出时手动生成)、长度不定(当然总长度必须小于单个变量最大长度8k)
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%i in (1001,1,1100) do set s=%%i&set var=!var!#!s:~-3!
  3.     for %%i in (A B C D) do (
  4.         set %%i=!var!&set _%%i=100
  5.         for /l %%j in (1 1 10) do set %%i.%%j=10
  6.   )
  7. set B.2=9&set C.8=9&set _B=99&set _C=99
  8. set X3= B-60&set X8= C-49&set B=!B:#060=!&set C=!C:#049=!
  9. for %%a in (A B C D) do (
  10.     for /l %%i in (1 1 10) do (
  11.     for /l %%j in (1 1 !%%a.%%i!) do (
  12.     set /a n=!random!%%_%%a*4
  13.     for %%b in ("!n!") do for %%c in ("!%%a:~%%~b,4!") do (
  14.     for /f "tokens=* delims=#0" %%d in (%%c) do (
  15.         set %%a=!%%a:%%~c=!
  16.         set /a _%%a-=1
  17.         set x%%i=!x%%i! %%a-%%d
  18. )))))
  19. for /l %%i in (1,1,10) do echo %%i班:&echo!x%%i!
  20. pause
复制代码
1

评分人数

    • batman: 说老实话,真不想给你分PB + 15

TOP

才发现我 33 楼的乱序方法居然是和 batman 22 楼一样的, 有巧合但也有特色: 做完代码才发现 33 楼居然没有用一个 if.

batman 好像认为 set 排乱序不太好, 我可真想不到还有什么更简洁的方式.

TOP

嘿嘿, 这次的 word 字数统计比 batman 22楼的少

  1. @echo off&setlocal enabledelayedexpansion
  2. for %%t in (A B C D) do (
  3.         for /l %%i in (1001 1 1100) do set "#%%t!random:~-2!%%i=%%i"
  4.         for /f "tokens=2 delims==" %%n in ('set #%%t') do set "U=!U!%%t-%%n "
  5.         set U=!U:-1=-!
  6.         set "U=!U:B-060 =!      "& set "U=!U:C-049 =!      "
  7.         for /l %%s in (0 60 540) do ( set /a V=%%s/60+1
  8.                 for %%c in (x-!V!) do set "%%c=!%%c!!U:~%%s,60!"
  9.         )
  10.         set "U="
  11. )
  12. set "X-10=!X-10:      =!!X-3:~60,6!!X-8:~120,6!"
  13. set X-3=!X-3:~0,60!B-060 !X-3:~66!& set "X-8=!X-8:~0,120!C-049 !X-8:~126!"
  14. set X&pause
复制代码
这次 100 个学生表的次序 采用了 set 输出排序, set 输出一系列变量是会按变量名的次序来排列的, 但事先安排 100 个变量名仅前部相同, 变量值却是 1--100 中的任意一个, 且没有变量值相同的情况, 而且 1--100 每个值都是安排到了一个随机生成的变量名的变量, 再用 set 输出, 输出的变量名是按正常次序来的, 但变量的值却成了无规则的乱序了, 部分示例如下:
#A0074=74
#A0134=34
#A0270=70
#A0352=52
#A0381=81
#A0497=97
#A0550=50
#A0553=53
#A063=3
#A0658=58

TOP

=。=  这两人编码靠后,干涉较多额。 我还是老老实实做简单的那个吧
goto 惯了
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set spec=#ABCD
  4. set /a m=1
  5. :main
  6. for /l %%a in (1,1,100) do (set i_%%a=%%a)
  7. set /a lp=1,range=100
  8. :lp
  9.     set /a tmpx=%random% %% range + 1
  10.     set /a class=!i_%tmpx%! %% 10 + 1
  11.     set class_%class%=!class_%class%! !spec:~%m%,1!%lp%
  12.     set /a i_%tmpx%=i_%range%
  13. if %lp% lss 100 (set /a lp+=1,range-=1 &goto :lp)
  14. if %m% lss 4 (set /a m+=1 &goto :main)
  15. for /l %%i in (1,1,10) do (echo class %%i = !class_%%i!)
  16. pause
复制代码


Yoshi, 重新了解了一下情况,果断放弃.=。=

[ 本帖最后由 523066680 于 2010-6-29 09:40 编辑 ]

TOP

目前只会做没有考虑后门的,而且效率不高。我觉得我的代码是新手最容易看的懂的。就贴出来了。
把x%%a=%%d !x%%a!中间的空格换为tab键。
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for %%a in (A B C D) do for /l %%b in (1,1,100) do set #%%a-!random!-%%a-%%b=0
  4. for /l %%a in (1,1,10) do (
  5.   for /f "tokens=3,4 delims=-=" %%b in ('set #') do (
  6.    for %%d in (%%b-%%c) do (
  7.     set /a m+=1
  8.     set /a n=m%%10+1
  9.     if !n! equ %%a set x%%a=%%d !x%%a!
  10. )
  11. )
  12. )
  13. for /l %%j in (1,1,10) do (
  14.   echo 第%%j班:
  15.   echo !x%%j!
  16. )
  17. pause
复制代码

[ 本帖最后由 sgaizxt001 于 2010-6-29 06:20 编辑 ]
1

评分人数

    • batman: 加分鼓励,加油PB + 5
努力学习,努力挣分

TOP

再发一个

:: 生成 1--100 的随机数序列, 删除掉 后门生编号, 平分进 10 个班,
:: 但 X-10 班会少分两个学生.
:: 将 3 班的第 1 个 B 类学生剪切给 10 班, 再把 B-060 加入 3 班
:: 将 8 班的第 1 个 C 类学生剪切给 10 班, 再把 C-049 加入 8 班
  1. @echo off&setlocal enableDelayedExpansion&mode con cols=126
  2. for /l %%i in (1001 1 1100) do set "sStu=!sStu!S-%%i"
  3. set "sStu=!sStu:-1=-!"
  4. for %%a in (A B C D) do (
  5.   set sS=!sStu:S=%%a!& set sS=!sS:B-060=!& set "sS=!sS:C-049=!"
  6.   set "UP=100" & if %%a geq B if %%a leq C set "UP=99"
  7.   for /l %%x in (1 1 10) do (for /l %%i in (1 1 10) do (
  8.       if !UP! gtr 0 ( set /a "start=!random!%%UP*5"
  9.         for %%s in (!start!) do (for %%c in (!sS:~%%s^,5!) do (
  10.           set "X-%%x=!X-%%x! %%c"& set "sS=!sS:%%c=!"& set /a UP-=1
  11. ) ) ) ) ) )
  12. echo 开后门之前:&set X-& set "X-10=!X-10!!X-3:~60,6!!X-8:~120,6!"
  13. set X-3=!X-3:~0,60! B-060!X-3:~66!& set "X-8=!X-8:~0,120! C-049!X-8:~126!"
  14. echo 开后门之后:&set X-&pause
复制代码

TOP

返回列表