通常、仕事に適した言語を常に選択するのは良いことですが、非常に不適切な言語で何かをしようとすることが有益な場合もあります。
- 問題をよりよく理解するのに役立ちます。思ったように解決する必要はないかもしれません。
- 言語をよりよく理解するのに役立ちます。たぶん、あなたが思っているよりも多くの機能をサポートしています。
そして、このアイデアを非論理的な結論に押し上げると、バッチ ファイルにクイックソートをどのように実装しますか? それは可能ですか?
通常、仕事に適した言語を常に選択するのは良いことですが、非常に不適切な言語で何かをしようとすることが有益な場合もあります。
そして、このアイデアを非論理的な結論に押し上げると、バッチ ファイルにクイックソートをどのように実装しますか? それは可能ですか?
結局のところ、それはあなたが思っているほど難しくありません。構文は非常に醜いですが、バッチ構文は、再帰、ローカル変数、驚くほど洗練された文字列の解析など、驚くべきことを実際に行うことができます。誤解しないでほしいのですが、これはひどい言語ですが、驚いたことに、完全に機能していないわけではありません。クイックソートについては何も学ばなかったと思いますが、バッチ ファイルについては多くのことを学びました!
いずれにせよ、ここにバッチ ファイルのクイック ソートがあります。私が書いているときと同じように、読みながらこの奇妙な構文を理解することを楽しんでいただければ幸いです。:-)
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
call :qSort %*
for %%i in (%return%) do set results=!results! %%i
echo Sorted result: %results%
ENDLOCAL
goto :eof
:qSort
SETLOCAL
set list=%*
set size=0
set less=
set greater=
for %%i in (%*) do set /a size=size+1
if %size% LEQ 1 ENDLOCAL & set return=%list% & goto :eof
for /f "tokens=2* delims== " %%i in ('set list') do set p=%%i & set body=%%j
for %%x in (%body%) do (if %%x LEQ %p% (set less=%%x !less!) else (set greater=%%x !greater!))
call :qSort %less%
set sorted=%return%
call :qSort %greater%
set sorted=%sorted% %p% %return%
ENDLOCAL & set return=%sorted%
goto :eof
コマンドラインでソートする一連の数字をスペースで区切って指定して呼び出します。例:
C:\dev\sorting>qsort.bat 1 3 5 1 12 3 47 3
Sorted result: 1 1 3 3 3 5 12 47
コードを理解するのは少し面倒です。基本的には標準のクイックソートです。重要な点は、数値を文字列 (貧弱な配列) に格納していることです。2 番目の for ループはかなりあいまいです。基本的に、配列を先頭 (最初の要素) と末尾 (他のすべての要素) に分割しています。Haskell は x:xs という表記でそれを行いますが、バッチ ファイルは /f スイッチで呼び出される for ループで行います。なんで?なぜだめですか?
SETLOCAL および ENDLOCAL 呼び出しを使用すると、ローカル変数を実行できます。SETLOCAL は元の変数の完全なコピーを提供しますが、ENDLOCAL を呼び出すとすべての変更が完全に消去されます。つまり、グローバルを使用して呼び出し元の関数と通信することさえできません。これは、醜い "ENDLOCAL & set return=%sorted%" 構文を説明しています。これは、ロジックが何を示していても実際には機能します。行が実行されたとき、行がまだ実行されていないため、並べ替えられた変数は消去されていません。その後、行が既に実行されているため、戻り値の変数は消去されていません。ロジカル!
また、面白いことに、変数は変更できないため、基本的に for ループ内で変数を使用することはできません。これにより、for ループを持つことのほとんどのポイントが削除されます。回避策は、機能する ENABLEDELAYEDEXPANSION を設定することですが、構文が通常よりもさらに醜くなります。名前だけで参照される変数が混在していることに注意してください。1 つの % を前に付けるか、2 つの % を前に付けるか、% で囲むか、! で囲みます。そして、変数を参照するこれらの異なる方法は、ほぼ完全に互換性がありません!
それ以外は比較的わかりやすいはず!
少し前に書いた、より読みやすいバージョンを次に示します。
@echo off
echo Sorting: %*
set sorted=
:sort
:: If we've only got one left, we're done.
if "%2"=="" (
set sorted=%sorted% %1
:: We have to do this so that sorted gets actually set before we print it.
goto :finalset
)
:: Check if it's in order.
if %1 LEQ %2 (
:: Add the first value to sorted.
set sorted=%sorted% %1
shift /1
goto :sort
)
:: Out of order.
:: Reverse them and recursively resort.
set redo=%sorted% %2 %1
set sorted=
shift /1
shift /1
:loop
if "%1"=="" goto :endloop
set redo=%redo% %1
shift /1
goto :loop
:endloop
call :sort %redo%
:: When we get here, we'll have already echod our result.
goto :eof
:finalset
echo Final Sort: %sorted%
goto :eof
例:
C:\Path> sort 19 zebra blah 1 interesting 21 bleh 14 think 2 ninety figure it out
生成:
Sorting: 19 zebra blah 1 interesting 21 bleh 14 think 2 ninety figure it out
Final Sort: 1 2 14 19 21 blah bleh figure interesting it ninety out think zebra