批处理 - 查找排列
我是批处理新手,我想知道是否可以按顺序查找所有数字组合。批处理 - 查找排列
在这种情况下,我有49个数字从1 - 49,我必须选择6个数字作为结果。
例如:
1 2 3 4 5 6
1 2 3 4 5 7
...
1 2 3 4 5 49
1 2 3 4 6 7
1 2 3 4 6 8
等等
这是我的旧代码:
@echo off > NEWFILE & setLocal EnableDelayedExpansion
set a=44
set b=45
set c=46
set d=47
set e=48
set f=49
for /L %%a in (1 1 !a!) do (
for /L %%b in (2 1 !b!) do (
for /L %%c in (3 1 !c!) do (
for /L %%d in (4 1 !d!) do (
for /L %%e in (5 1 !e!) do (
for /L %%f in (6 1 !f!) do (
echo.%%a %%b %%c %%d %%e %%f
))))))) >> NEWFILE
goto :EOF
但是它返回:
1 2 3 4 5 6
1 2 3 4 5 7
...
1 2 3 4 5 49
1 2 3 4 6 6
两个6的出现。
我似乎无法解决它,请帮助,非常感谢!
当你发布一个问题时,你应该发布你的努力来解决它,描述你使用的方法和问题;否则,你可能会得到根本不需要做任何的解释类似的答案,像这样的:
编辑:随着用户dbenham和aschipfl指出,我原来的代码有一个小错误:在set /A i=M-1
行应的:nextSet
之后放置标签。这是正确的代码:
@echo off
setlocal EnableDelayedExpansion
set "N=%1"
set "M=%2"
set "line="
for /L %%i in (1,1,%M%) do (
set "C[%%i]=%%i"
set "line=!line! ^!C[%%i]^!"
)
:nextSet
set /A i=M-1
for /L %%j in (!C[%M%]!,1,%N%) do (
set "C[%M%]=%%j"
echo %line%
)
:nextPos
set "C=!C[%i%]!"
if %C% equ %N% (
set /A i-=1
if !i! equ 0 goto :EOF
goto nextPos
)
for /L %%i in (%i%,1,%M%) do (
set /A C+=1,C[%%i]=C
)
if !C[%M%]! gtr %N% goto nextPos
goto nextSet
显然,更正后的代码生成结果的数量大得多,这版本是特别慢...... :(
下新版本采用完全相同的代码dbenham的解决方案;它唯一的好处是,你可以更改用来在一个非常简单的方法来产生结果的参数:
@echo off
setlocal EnableDelayedExpansion
set "N=%1"
set "M=%2"
set /A j=N-M, prev=0
set "for=" & set "line=" & set "endfor="
for /L %%i in (1,1,%M%) do (
set /A j+=1
set "for=!for! set /A start=!prev!+1 & for /L %%%%i in (^!start^!,1,!j!) do ("
set "line=!line! %%%%i"
set "endfor=!endfor!)"
set "prev=%%%%i"
)
REM ECHO !FOR! echo !LINE! %ENDFOR%
%for% echo %line% %endfor%
输出例如:
C:\> test.bat 6 4
1 2 3 4
1 2 3 5
1 2 3 6
1 2 4 5
1 2 4 6
1 2 5 6
1 3 4 5
1 3 4 6
1 3 5 6
1 4 5 6
2 3 4 5
2 3 4 6
2 3 5 6
2 4 5 6
3 4 5 6
为了让您的结果,使用:test.bat 49 6
2ND EDIT:添加更快的方法
当要解决的问题是过程时间过长t akes,一个明显的选择是使用更快的编程语言。下面使用JScript的解决方案,即是有点类似于批处理文件编程:
@if (@CodeSection == @Batch) @then
@echo off
echo Start: %time%
cscript //nologo //E:JScript "%~F0" > result.txt
echo End: %time%
goto :EOF
@end
// JScript code section
for (var A=1; A <= 44; ++A) {
for (var B=A+1; B <= 45; ++B) {
for (var C=B+1; C <= 46; ++C) {
for (var D=C+1; D <= 47; ++D) {
for (var E=D+1; E <= 48; ++E) {
for (var F=E+1; F <= 49; ++F) {
WScript.Echo(A,B,C,D,E,F);
}
}
}
}
}
}
这是一个批次的JScript混合脚本;用.BAT扩展名保存。这个程序在我便宜又慢的笔记本电脑上用不到9分钟的时间生成了一个有13983816行的239 MB文件。
您的算法存在严重问题。正确的结果应该有13,983,816行,而不是4,774。我注意到你的输出只有39行,其中第二个值是3,当用参数49和6调用时。 – dbenham
据我所知,修复应该很简单:将标签':nextSet'向上移动一行在行'set/A i = M-1'之前。 – aschipfl
为了提高性能,我打算提出以下更改:1.在'if%C%'块之后移动行'set“C =!C [%i%]!”'; 2.在标签':nextPos'后插入'set/A C = C [%i%] + i-M'; 3.用'if%C%gtr%N'替换'if%C%equ%N%'; 4.删除行'if!C [%M%]! gtr%N%';然而,虽然这些修改避免了额外的'goto'循环和多个'for/L %% i'循环,他们使我的电脑上的代码变得更加慢65%左右(将输出重定向到“nul”并使用参数'20'和'5')。你知道这是为什么吗? 'set/A'是一个如此缓慢的野兽? – aschipfl
未来,请展示一些代码,证明您试图自己解决问题,显示卡住的位置,输出的位置与预期不符,等等。问题类似“这是我的要求。对我而言“在这里一般不受欢迎。如果你没有显示任何代码,你得到一个upvote是超越我,但c'est la vie。
在这种情况下,我发现这个问题很有趣,所以我想我会继续前进,让你开始。接受挑战。这是一种方法。
@echo off
setlocal enabledelayedexpansion
set "series=1 2 3 4 5 6"
:loop
echo %series%
if "%series%"=="44 45 46 47 48 49" goto :EOF
for /f "tokens=1-6" %%a in ("%series%") do (
set /a i1=%%a, i2=%%b, i3=%%c, i4=%%d, i5=%%e, i6=%%f+1
if !i6! gtr 49 set /a i5+=1, i6=i5+1
if !i5! gtr 48 set /a i4+=1, i5=i4+1, i6=i5+1
if !i4! gtr 47 set /a i3+=1, i4=i3+1, i5=i4+1, i6=i5+1
if !i3! gtr 46 set /a i2+=1, i3=i2+1, i4=i3+1, i5=i4+1, i6=i5+1
if !i2! gtr 45 set /a i1+=1, i2=i1+1, i3=i2+1, i4=i3+1, i5=i4+1, i6=i5+1
set "series=!i1! !i2! !i3! !i4! !i5! !i6!"
)
goto loop
这里的另一个解决方案应该是更有效的。
@echo off
setlocal enabledelayedexpansion
set "series=1 2 3 4 5 6"
set total=0
for /L %%a in (1,1,44) do (
set /a i2 = %%a + 1
for /L %%b in (!i2!, 1, 45) do (
set /a i3 = %%b + 1
for /L %%c in (!i3!, 1, 46) do (
set /a i4 = %%c + 1
for /L %%d in (!i4!, 1, 47) do (
set /a i5 = %%d + 1
for /L %%e in (!i5!, 1, 48) do (
set /a i6 = %%e + 1
for /L %%f in (!i6!, 1, 49) do (
rem // Uncomment this echo to watch the progress (severely decreases efficiency)
rem echo %%a %%b %%c %%d %%e %%f
set /a total += 1
)
)
)
)
)
echo Total so far: !total!
)
rem // Should have gone through 13983816 iterations
该问题是计算密集型的,因为有13,983,816个独特的排列。 (请参阅https://en.wikipedia.org/wiki/Lottery_mathematics#Calculation_explained_in_choosing_6_from_49。)
Rojo答案应该可以工作,但GOTO和重复的FOR/F解析和IF逻辑会显着降低速度。
如果使用嵌套的FOR/L循环,代码会快得多。
@echo off
setlocal enableDelayedExpansion
for /l %%A in (1 1 44) do (
set /a start=%%A+1
for /l %%B in (!start! 1 45) do (
set /a start=%%B+1
for /l %%C in (!start! 1 46) do (
set /a start=%%C+1
for /l %%D in (!start! 1 47) do (
set /a start=%%D+1
for /l %%E in (!start! 1 48) do (
set /a start=%%E+1
for /l %%F in (!start! 1 49) do (
echo %%A %%B %%C %%D %%E %%F
)
)
)
)
)
)
如果让脚本将结果打印到屏幕上,这仍然会让人无法忍受。我估计我的机器需要1.25小时。将输出重定向到文件大约快5倍,大约15分钟。
“关闭”问题的方法是给出答案的反馈并选择一个作为答案;这样做会将问题标记为“回答”,并为OP和回答者提供信誉点。在问题标题中添加“CLOSED”或任何其他类似的横幅是本网站不使用的做法。 – Aacini