回答:
PowerShellではスペースを多くスキップできます。必要ないと思われる場合は、おそらく必要ありません。これは比較で特に役立ちます。
例:
$x-eq$i-and$x-ne9
対
$x -eq $i -and $x -ne 9
複数の結果がswitch
得られる可能性がある単一のテストの結果に基づいてスクリプトを分岐する必要がある場合、ifステートメントと一致するか、またはそれを破ることがあります。
例(スイッチとif / else-tie):
if($x%2-eq0){'even'}else{'odd'}
対
switch($x%2){0{'even'}1{'odd'}}
または(スイッチとif / elseif / else-スイッチが15勝つ):
if($x%2-eq0){'even'}elseif($x%2-eq1){'odd'}else{'error'}
対
switch($x%2){0{'even'}1{'odd'}2{'error'}}
上記のモジュロ演算のように、スイッチが実際に特定の計算結果に基づいている場合、スイッチを完全に配列に置き換えることができます。ここでは、さらに13文字を節約し、元の2オプションのif / elseステートメントよりもさらに短くなっています。(このビットについてはDanko Durbicに感謝します。)
('even','odd','error')[$x%2]
特定のコマンドを大量に使用する場合、特に既存の短縮エイリアスがない場合は、早い段階で1文字のエイリアスを設定します。
例:
nal g Get-Random;g 10;g 10;g 10
対
Get-Random 10;Get-Random 10;Get-Random 10
('even','odd')[$x%2]
ご参考までに。
括弧で変数を定義するコマンドをカプセル化すると、変数の定義を他のコマンドに直接フィードできます。
たとえば、次のようにすると、1回のショットで$ xを設定し、$ xの値に基づいて$ yを設定できます。
$y=($x=1)+1
これの代わりに:
$x=1;$y=$x+1
これで$ hを設定して出力できます:
($h='Hello World!')
これの代わりに:
$h='Hello World!';$h
($x=New-Object Windows.Forms.Form).Controls.Add($t)
配列を指定すると、スイッチはループのように機能します。例えば:
$FooBarMeh='a','b','c'
switch ($FooBarMeh)
{
'a'{'FOO'}
'b'{'BAR'}
default{'MEH'}
}
出力されます:
FOO
BAR
MEH
これがどこで役立つかはよくわかりませんが、いつか誰かにとって便利になると思います。
ForEach-Object
し、switch
その中を。たとえば、テキストファイルのクイックパーサーを作成するのに非常に便利なコードは(実際には)、どの正規表現が行に一致するかによって異なる処理を行う必要があります。
switch -File $path
は何のためです
[math]::pow
乗算に置き換えます。の代わりに
[math]::pow($a,$b)
あなたは書ける
"$a*"*$b+1|iex
これは、整数指数> = 0で機能します。
値のコレクションの最大値または最小値を見つけたいですか?試した
(...|measure -ma).Maximum
または
(...|measure -mi).Minimum
既に?
最後または最初のアイテムを並べ替えて使用するだけです:
(...|sort)[-1] # maximum
(...|sort)[0] # minimum
0
、1
、2
、3
、4
、5
、6
、7
、8
または9
、その代わりに、既知の長さを書くためにバイトを保存します-1
。
悲しいことに、パラメータとは異なり、プロパティ/メソッド(ドットでアクセスされるもの.
)は通常、その明確な形式に短縮することはできません。
ただし、特定のコマンドレットはプロパティ名を操作し、ワイルドカードを使用できます。%
また?
、ほとんど知られていないパラメーターセットがあり、有用な場合があります。
通常、スクリプトブロックを渡してでアイテムを参照し$_
ますが、プロパティ名を受け取り、ワイルドカードを受け入れるこれらの別の形式があります。
$o|select Le*
$o|%{$_.Length}
配列自体のプロパティである.Length
ため、通常は配列で機能するv3マジックを使用できないようなLength
プロパティでは、上記の2つを使用して個々のメンバーの長さを取得できます。select
短い少しで来ます。
ただし%
、プロパティ名を直接受け取り、その値を返すことができます。
$a|% Length
ワイルドカードで短縮できます。ワイルドカードは単一のプロパティ(またはメソッド、詳細は後ほど)に解決する必要があるため、解決しない場合、解決できるメンバーを正確に示す有用なエラーをスローします。
の場合Length
、Le*
通常は最短です。単一の文字列であっても、このメソッドはプロパティを使用するよりも1バイト短くなります。
$a.Length # 9 #(doesn't work on array)
$a|%{$_.Length} # 15
$a|% Le* # 8
しかし、これで何をしているのかによっては、これはさらに悪くなる可能性があります。できます$a.Length*5
が、パイプライン式で行うにはラップする必要があり($a|% Le*)*5
ます。配列に反する場合でも、それは価値があるかもしれませんが、ポイントは、それが常にまっすぐな置換として適切であるとは限らないということです。
メソッドでも機能し()
、フルネームを同じ長さにすることはできますが、場合によってはラップする必要があるという上記の制限と同じです。メソッドにはパラメーターを受け取らないオーバーロードが必要です(引数をメソッド名の後に配置することで引数を渡すことができます)。
$a.ToUpper() # 12
$a|% *per # 9
引数あり:
'gaga'-replace'g','r' # 21
'gaga'|% *ce g r # 16
これらは、-replace
演算子が正規表現の置換を行うという点で厳密には同じではありませんが、文字列の置換を行うだけの場合、メソッドを使用する方が(今では)短くなります。文字列はメソッド引数ではなくコマンドレット引数であるため、引用符で囲む必要はありません。
?
(部分的な)プロパティ名も使用でき、「演算子」を(スイッチパラメーターの形式で)適用できます。ここでもWhere-Object
、プロパティ名が十分に長く一意である場合、これは標準のスクリプトブロックアプローチを使用するよりも短くなる可能性があります。
$a|?{$_.Length-gt5} # 19
$a|? Le* -GT 5 # 14
($a|% Le*)-gt5 # 14 - Lengths, not objs
.ToString()
!
セミコロンと改行は交換可能です。ゴルフされたコードは、1行に詰まらない限り読みやすいことがよくあります。また、長さは同じです(PowerShellが問題なく処理する改行としてU + 000Aを使用する場合)。
Get
動詞が暗示されます。これはany Get-Frob
をに短縮できFrob
ます。頻繁に競合するのはdate
またはrandom
です。
パスにGNUユーティリティ(またはクラッシュする他のネイティブプログラム)がある可能性があるため、これは場合によっては正しく機能しないことに注意してください。その場合のコマンドルックアップの順序は、Get-
削除されたコマンドレットを考慮する前にネイティブプログラムを優先するようです。
PS Home:\> date
Freitag, 15. November 2013 07:13:45
PS Home:\> $Env:Path += ';D:\Users\Joey\Apps\GnuWin32\bin'
PS Home:\> date
Fr Nov 15 07:14:13 W. Europe Standard Time 2013
nal g Get-Random
後で文字を保存するためのスクリプトがあります。それを変更するnal g Random
と、スクリプトが無期限にハングアップします(または、少なくとも処理に膨大な時間を要します-終了するのを待つ忍耐はありませんでしたが、元のフォームよりも桁違いに長くかかっています)中止する前に)。
Measure-Command
回の短い呼び出し(100回Get-Random
対random
)は、約500倍遅いことを示しています。正直に言うと、私はそれを前に知りませんでした。ただし、特に繰り返しが多いループでは、このことを念頭に置いておくとよいでしょう。そうは言っても、ゴルフのコードは短くはなく、速くなければなりません(つまり、プロジェクトオイラーの問題に対する答えを2日間待たなければならないのは残念です)。
Get-Variable
対gv
と同様の比較を得ました。
Get-
ます。これは、実行時にかなりひどく肥大し、長さをわずか4文字節約できます。
for
ループのヘッダーには、0〜3つのステートメントを含めることができます。
無限ループ:
for(){}
初期化を伴うループ:
for($n=0){}
初期化および終了条件を使用したループ:
for($n=0;$n-lt7){}
このような場合、常に正確に3つのステートメントを必要とするCのような言語とは対照的に、末尾の追加のセミコロンは省略できます(言語仕様で明示的に記述されているため、実装の詳細ではありません)。
これによりwhile
、少し短くなります。比較する
while(...){}
そして
for(;...){}
追加のボーナスを使用すると、前の行(ある場合)をfor
追加コストなしで(さらにはキャラクターを保存することなく)そのまま使用できます。
2つの値しか持たないことがわかっている配列を割り当てる場合は、インデックスを使用しないでください。
このようなもの:
$a="apple","orange"
$a[0] # apple
$a[1] # orange
簡単にこれに変えることができます:
$a,$o="apple","orange"
$a # apple
$o # orange
これは、配列の最初の要素だけが必要な場合にも役立ちます。
$a,$b=1..10
$a # 1
$b # 2..10
$a="apple";$o="orange"
は長さが同じです。セパレーターを使用して文字列にすべての要素を入れて-split
から使用するなど、かなりうまく最適化できる場合があります(単項で-split
十分なので、スペースをセパレーターとして使用するのが最適です)。
文字列へのキャスト:
[string]$x
対
"$x"
このような文字列へのキャストは、結合する代わりに、文字列の配列を平坦化するためにも使用できます。
$a = @('a','b','c')
$a -join ' '
対
$a = @('a','b','c')
"$a"
文字列を数値型にキャストする:
[int]$x [float]$x
対
+$x
また、PowerShellは常に左オペランドの型を使用して、適用される式と変換の最終型を決定することを知っていると非常に便利です。
'1'+2 -> '12'
1+'2' -> 3
不要なキャストがどこにあるかを判断するのに役立ちます。
パラメーターの完全な名前を常に提供する必要はなく、一部のパラメーターは定位置であることを忘れないでください。
Get-Random -InputObject (0..10)
...にトリミングできます...
Get-Random -I (0..10)
...この場合、InputObject
このコマンドの他の有効なパラメーターから一意に識別するには「I」で十分であるためです。
さらにトリムして...
Get-Random (0..10)
...なぜならInputObject
、位置パラメータだからです。
パイプは、特に括弧の必要性を取り除くことができる場合、パラメーターとしてオブジェクトを供給するよりも通常短くなります。乱数ジェネレーターをさらにトリムしましょう...
0..10|Get-Random
また、コマンドを変更できない場合でも、同じことを実現する他の方法に注意してください。上記の場合、これを行うことができます:
Get-Random 11
または、別の提案を組み込む*:
Random 11
**注:Get-
コマンド名を省略すると、実行時間が約50,000%大きくなる可能性があります。コマンドが1回だけ必要な場合は悪くありませんが、長いループで使用する場合は注意してください。*
そして、それは単純なコマンドをそのサイズの3分の1にノックする方法です。
偽の三項演算子。if
ステートメントから直接割り当てることができます:
$z=if($x-eq$y){"truth"}else{"false"}
ただし、2要素の配列を使用し、テストを使用してインデックスを作成できます。$ falseyの結果は要素0を取得し、$ truthyの結果は要素1を取得します。
$z=("false","true")[$x-eq$y]
NB。これは実際に配列のインデックス付けを行っており、テストの結果が整数にキャストできる値になった場合、配列の境界外の項目を要求して$ nullを取得し!(test)
、強制的に行う必要がありますオプションを逆にして、結果をブールにキャストします。
$()
。基本的に、コマンドおよびステートメントから作成されたパイプラインを式として使用することには違いがありました。少なくともPowerShell 5では、もうなくなっているようです。–
文字列を必要とする演算子の引数として数値を使用する場合、その数値を直接使用できます。比較する
...-join'0'
対
...-join0
作品-split
だけでなく、。引数は常に最初に文字列に変換されます。
-replace
も同様に機能します。
-replace
また、あなたがマッチを削除するwhebなし第二引数で動作します
自動変数は、TrueとFalseのためのブール値を持っている$true
し、$false
しかし、あなたは論理的ではない演算子使用して同様の結果を得ることができます!
し、整数0と1(またはゼロ以外の整数。)
PS C:\Users\matt> !1
False
PS C:\Users\matt> !0
True
ほとんどすべてのPowerShell式はブール値として評価できます。そのため、特定のデータがどのように評価されるかを知っている限り、ブール値を取得でき、明示的にキャストする必要はありません。これらを行うときは、LHS値に注意してください。
他の例もありますが、キャストを行うことで簡単にテストできます
PS C:\Users\matt> [bool]@(0)
False
$null
はfalseです。空の文字列(および空の文字列に設定された変数)は偽です。その後、FizzBuzzで使用されていたように、これを使用して、インデックスをショートカットに配列にショートカットすることができます(たとえば、if
/を実行する場合else
)。
int
s を使用するのは簡単です
bool
。あなたは使用することができます0
し、1
全く同じように。暗黙的な変換は、その点で非常に役立ちます(特定の演算子でしばしば強制できます)。
Invoke-Expression
またGet-Random
、引数の代わりにパイプライン入力を取得することもできます。
以下のためにiex
、このいくつかの表現に括弧を保存することができます:
iex 1..5-join'+' # won't work
iex(1..5-join'+') # does work, but has extra parentheses
1..5-join'+'|iex # doesn't need the parentheses
この場合random
、一般的なケースを少し最適化できます:
random -mi 10 31 # gets a random integer between 10 and 30
10..30|random # much better :-)
(random 21)+10 # if needed in another expression that doesn't require extra
# parentheses
後者の使用方法では、リストからアイテムを選択するだけです。-c
引数には、単一選択以上を許可するように与えることができます。
関数を使用する代わりに、繰り返しスクリプトブロックを変数に保存することを検討してください。
関数を変数として書き直すと変数さえも不要になることに気づく前に、これを使用してRock、Paper、Scissors実装の一部の文字を保存しました。ただし、これは実際に同じコードを複数回実行している他のスクリプトにも役立ちます。
function Hi{echo 'Hello, World!'};Hi
対
$Hi={echo 'Hello, World!'};&$Hi
params(...)
ないと、関数定義が保存するよりも多くのスペースを占有します。関連:使用をfilter
介してfunction
、あなたがそうすることができるとき。
$args
の必要性を回避するために使用できますparams
。すなわち$x={$args[0]+2}
(または$x={2+"$args"}
); 状況によっては、1キャラクターまたは2セーブする場合があります。また、これを複数の$x={$a,$b=$args;$a+$b+3}
$s|% t*y
代わり[char[]]$s
に、文字列をchar配列に分割するために使用できます。与えられたTessellatingHecklerの答え:% t*y
に展開| ForEach-Object -Method ToCharArray
当量。の"$args".ToCharArray()
たとえば、比較
$s|% t*y
そして
[char[]]$s
そして
$s.ToCharArray()
$args
特に便利です:$args|% t*y
%
メンバーにこのトリックを数回使用しましたが、私のゴルフのほとんどはその機能よりも前のものです;-)。これも非常に一般的な手法です。必要なプロパティ/メソッドに一致する(実際のものより短い)文字/ワイルドカードの組み合わせを見つけてみてください。
$s|% *per
for $s.toUpper()
および$s|% *wer
for $s.toLower()
。私はそれが非常にきちんとしていることに同意します。
1から10までのすべての偶数を追加するとします... 2+4+6+8+10=30
1..10|%{if($_%2-eq0){$o+=$_}};$o
ブール否定を使用してそれを短くすることができます
1..10|%{if(!($_%2)){$o+=$_}};$o
バイトを保存しますが、代わりにブール値を暗黙的にintにキャストして、条件をアキュムレータにロールする方法はどうですか
1..10|%{$o+=$_*!($_%2)};$o
この例では6バイトを節約します。
PowerShellでの浮動小数点数の整数への変換は、ちょっとした地雷原です。デフォルトでは、変換は、常に小数を切り捨てて小さい整数を残すわけではなく、人々がカジュアルに行うように常に0.5を次の数に切り上げるわけではないBankers Roundingを行います。驚くべきこと、例えば
PS C:\> [int]1.5
2
PS C:\> [int]2.5
2
codegolf計算を中断します。他の多くの一般的な言語は切り捨て丸めを行うため、ゴルフの質問ではしばしば切り捨てが必要です。あなたは[Math]::Floor()
次善の策として手を伸ばすかもしれませんが、これは正の数の切り捨てと同じようにしか振る舞わないことに注意してください。[Math]::Truncate()
PSの動作を他の言語のデフォルトの丸めに合わせるために必要なものですが、多くの文字があります。
小数点以下の数字を正規表現に置き換えると、数文字を節約できます。
[Math]::Truncate(1.5)
[Math]::Floor(1.5)
1.5-replace'\..*'
[Math]::Truncate($a)
[Math]::Floor($a)
$a-replace'\..*'
$a.split('.')[0] # literal character split, not regex pattern split
出力がなんらかの方法でミラーリングされるような多くのアスキーアートの課題で役立ちます。
あなたが持っていると仮定します
$a=1,2,3,4,5
従来の反転方法は長くて退屈で、すぐに使用できるようにパイプラインに配列を残しません。
[array]::reverse($a)
逆の順序で配列に直接インデックスを付けると、結果がパイプラインに残るため、数バイトは節約されますが、それでもかなり長くなります。
$a[($a.count-1)..0]
代わりに、ループを試してください
$a|%{$a[-++$i]}
PowerShell Core 6以降では、文字の範囲も使用できます。
'a'..'z'
より面倒なものを置き換えることができます
0..25|%{[char]($_+97)}
[char[]](65..90)
は、アルファベットを生成する便利な方法でもあります