Welche allgemeinen Tipps haben Sie zum Golfen in Windows PowerShell? Ich bin auf der Suche nach Ideen, die auf Code-Golf-Probleme im Allgemeinen angewendet werden können, die zumindest etwas PowerShell-spezifisch sind (z. B. "Kommentare entfernen" ist keine Antwort). Bitte posten Sie einen Tipp pro Antwort.
- Fast wörtlich genommen aus Marcogs Frage .
code-golf
tips
powershell
Joey
quelle
quelle
Antworten:
Potenzen von 10 Literalen mit wissenschaftlicher Notation:
Potenzen von 2 Litern:
Könnte sich als nützlich erweisen.
quelle
Wenn Sie eine Schleife ausführen müssen und genau wissen , wie oft sie jedes Mal ausgeführt werden muss, sollten Sie ein Array zusammenhängender Ganzzahlen
ForEach-Object
über den%
Alias weiterleiten, anstatt sie zu verwendenfor
.for($x=1;$x-le10;$x++){
...}
vs
1..10|%{
...}
quelle
Sie können Leerzeichen überspringen viel in Powershell. Wenn es sich so anfühlt, als ob es nicht gebraucht werden könnte, ist es das möglicherweise nicht. Dies ist besonders nützlich bei Vergleichen.
Beispiel:
gegen
Wenn Sie Ihr Skript basierend auf dem Ergebnis eines einzelnen Tests verzweigen müssen, der mehrere Ergebnisse haben
switch
kann , kann eine if-Anweisung manchmal übereinstimmen oder übertroffen werden.Beispiel (switch vs. if / else - tie):
gegen
Oder (switch vs. if / elseif / else - switch gewinnt mit 15):
gegen
Wenn der Schalter tatsächlich auf bestimmten mathematischen Ergebnissen basiert, wie der obigen Modulo-Operation, können Sie den Schalter vollständig durch ein Array ersetzen. Hier werden weitere 13 Zeichen gespeichert und es ist sogar kürzer als die ursprüngliche if / else-Anweisung mit zwei Optionen. (Danke an Danko Durbic für dieses Stück.)
Wenn Sie einen bestimmten Befehl häufig verwenden, insbesondere einen Befehl ohne bereits vorhandenen Kurznamen, richten Sie frühzeitig einen Einzelzeichen-Alias ein.
Beispiel:
gegen
quelle
('even','odd')[$x%2]
Zu Ihrer Information.Wenn Sie den Befehl, der eine Variable definiert, in Klammern einschließen, können Sie die Definition der Variablen direkt an andere Befehle weitergeben.
Zum Beispiel können Sie $ x und dann $ y basierend auf dem Wert von $ x in einer Einstellung wie folgt festlegen:
An Stelle von:
Du kannst $ h setzen und damit ausgeben:
An Stelle von:
quelle
($x=New-Object Windows.Forms.Form).Controls.Add($t)
Ein Switch kann sich wie eine Schleife verhalten, wenn er ein Array erhält. Zum Beispiel:
Wird ausgeben:
Ich bin nicht ganz sicher, wo dies nützlich sein wird, aber ich gehe davon aus, dass es für jemanden eine Weile nützlich sein wird.
quelle
ForEach-Object
und einswitch
in das benötigen . Es ist zum Beispiel (in der realen Welt) Code, der sich sehr gut zum Schreiben schneller Parser von Textdateien eignet, bei denen Sie verschiedene Dinge tun müssen, je nachdem, mit welcher Regex eine Zeile übereinstimmt.switch -File $path
ist fürDurch
[math]::pow
Multiplikation ersetzen . Anstatt vonDu kannst schreiben
Dies funktioniert für ganzzahlige Exponenten> = 0.
quelle
iex
... Alias fürInvoke-Expression
Vergleichsoperatoren bearbeiten Wertesammlungen, indem sie übereinstimmende Werte zurückgeben:
wird ergeben
3
,4
und5
. In einigen Fällen kann dies dazu beitragen, eine ansonsten längere Zeit zu sparen|?{$_...}
.-match
ist auch ein Vergleichsoperator.quelle
1..5-gt2
Verwenden Sie nach Möglichkeit Aliase. Es gibt eine Reihe von nützlichen:
quelle
Möchten Sie das Maximum oder Minimum einer Wertesammlung ermitteln? Versucht
oder
bereits?
Einfach sortieren und den letzten oder ersten Artikel verwenden:
quelle
0
,1
,2
,3
,4
,5
,6
,7
,8
oder9
wäre es ein Byte speichert die bekannte Länge statt zu schreiben-1
.Kürzen von Eigenschaftennamen
Leider können Eigenschaften / Methoden (auf die mit einem Punkt zugegriffen wird
.
) im Gegensatz zu Parametern normalerweise nicht auf ihre eindeutige Form verkürzt werden.Bestimmte Cmdlets können jedoch mit Eigenschaftsnamen und Platzhaltern arbeiten, und es gibt wenig bekannte Parametersätze von
%
und?
die können nützlich sein.Normalerweise übergeben wir einen Skriptblock und verweisen auf das Element mit
$_
, aber es gibt auch eine andere Form, die einen Eigenschaftsnamen annimmt und einen Platzhalter akzeptiert.Mit einer Eigenschaft wie der können
.Length
wir nicht die v3-Magie verwenden, die normalerweise für ein Array funktioniert, daLength
es sich um eine Eigenschaft des Arrays selbst handelt. Daher können die beiden oben genannten verwendet werden, um die Längen der einzelnen Elemente abzurufen. Dasselect
kommt etwas kürzer rein.Aber
%
kann einen Eigenschaftsnamen nehmen direkt und zurück , dass Wert:Welches kann mit Wildcards gekürzt werden. Der Platzhalter muss in eine einzelne Eigenschaft (oder Methode, dazu später mehr) aufgelöst werden. Andernfalls wird ein hilfreicher Fehler ausgegeben, der genau angibt, für welche Mitglieder er aufgelöst werden könnte.
Im Fall von
Length
,Le*
ist in der Regel die kürzeste. Selbst bei einer einzelnen Zeichenfolge ist diese Methode 1 Byte kürzer als die Verwendung der Eigenschaft.Aber je nachdem, was Sie damit machen, kann es schlimmer sein. Sie können dies
$a.Length*5
nur mit dem Pipeline-Ausdruck tun, den Sie umbrechen müssten($a|% Le*)*5
. Vielleicht lohnt es sich trotzdem, wenn es gegen ein Array ist, aber der Punkt ist, dass es nicht immer als direkte Substitution geeignet ist.Es funktioniert auch mit Methoden, und Sie können das weglassen
()
, wodurch ein vollständiger Name dieselbe Länge hat, aber dieselbe Einschränkung wie oben, dass er manchmal umgebrochen werden muss.Die Methode muss eine Überladung haben, die keine Parameter akzeptiert(Sie können Argumente übergeben, indem Sie sie hinter den Methodennamen setzen, was wirklich gut ist):Mit Argumenten:
Dies ist nicht unbedingt dasselbe, da der
-replace
Operator einen regulären Ausdruck ersetzt. Wenn Sie jedoch nur einen String ersetzen, kann die Verwendung der Methode (jetzt) kürzer sein. Es ist hilfreich, wenn die Zeichenfolgen Cmdlet-Argumente anstelle von Methodenargumenten sind, sodass sie nicht in Anführungszeichen gesetzt werden müssen.Where-Object-Eigenschaften
?
kann auch (teilweise) Eigenschaftsnamen annehmen und einen "Operator" darauf anwenden (in Form von Schalterparametern). Dies kann wiederum kürzer sein als die Verwendung des Standard-Where-Object
Scriptblock-Ansatzes, wenn der Eigenschaftsname lang und eindeutig genug ist.quelle
.ToString()
!Auf dem langen Weg eine Summe finden:
Ein kürzerer Weg:
Und noch kürzer:
quelle
Semikolons und Zeilenumbrüche sind austauschbar. Golf-Code ist oft besser lesbar, wenn er nicht in einer einzigen Zeile eingeklemmt ist. Und die Länge bleibt gleich (vorausgesetzt, Sie verwenden U + 000A als Zeilenumbruch, den PowerShell problemlos verarbeitet).
quelle
Das
Get
Verb ist impliziert. Das kann man beliebigGet-Frob
auf gerade verkürzenFrob
. Häufige Konkurrenten sinddate
oderrandom
.Beachten Sie, dass dies in einigen Fällen nicht richtig funktioniert, da Sie möglicherweise GNU-Dienstprogramme in Ihrem Pfad haben (oder andere native Programme, die in Konflikt geraten). In diesem Fall scheint die Reihenfolge der Befehlssuche das native Programm vorzuziehen, bevor Cmdlets mit dem
Get-
entfernten Befehl berücksichtigt werden:quelle
nal g Get-Random
das später mit dem Speichern von Zeichen beginnt . Wenn Sie es aufnal g Random
ändern, bleibt das Skript auf unbestimmte Zeit hängen (oder die Verarbeitung dauert zumindest übermäßig lange). Ich hatte nicht die Geduld, darauf zu warten, dass es beendet wird, aber es dauert mehrere Größenordnungen länger als das ursprüngliche Formular bevor ich abbreche).Measure-Command
Aufrufe (100 MalGet-Random
vs.random
) sagen mir, dass es ungefähr 500 Mal langsamer ist. Ich wusste das vorher nicht, um ehrlich zu sein. Aber es ist gut, sich daran zu erinnern, besonders in Schleifen mit vielen Iterationen. That being said, golfed Code sollte kurz sein, nicht schnell ( das wird gesagt, es saugt nach einer Antwort auf ein Projekt Euler Problem zu haben bis zwei Tage warten).Get-Variable
gegengv
und bekam einen ähnlichen Vergleich.Get-
. Das ist eine ziemlich aufgedunsene Laufzeit bei einer Ersparnis von nur 4 Zeichen Länge.for
Schleifen können zwischen 0 und drei Anweisungen im Header haben:Endlosschleife:
Schleife mit Initialisierung:
Schleife mit Initialisierungs- und Endebedingung:
In solchen Fällen können die zusätzlichen Semikolons am Ende weggelassen werden (dies ist ausdrücklich in der Sprachspezifikation angegeben , es handelt sich also nicht um ein Implementierungsdetail), im Gegensatz zu C-ähnlichen Sprachen, für die immer genau drei Anweisungen erforderlich sind.
Dies macht auch
while
ein bisschen kürzer. Vergleichen Sieund
Mit dem zusätzlichen Bonus, dass Sie in einer vorherigen Zeile (falls vorhanden)
for
auch ohne zusätzliche Kosten (und sogar Speichern eines Charakters) bleiben können .quelle
Wenn Sie ein Array zuweisen, von dem Sie wissen, dass es nur zwei Werte enthält, verwenden Sie keine Indizierung.
Etwas wie das:
Kann leicht in diese umgewandelt werden:
Dies kann auch nützlich sein, wenn Sie nur das erste Element eines Arrays benötigen:
quelle
$a="apple";$o="orange"
ist die Länge identisch. Es sind die längeren Arrays, die manchmal recht gut optimiert werden können, z. B. indem alle Elemente in einen String mit einem Trennzeichen eingefügt und dann verwendet werden-split
(am besten Leerzeichen als Trennzeichen verwenden, da dann das Unäre-split
ausreicht).Casting zum String:
gegen
Das Umwandeln in einen String wie diesen kann auch verwendet werden, um ein Array von Strings zu reduzieren, anstatt sie zu verbinden:
gegen
Zeichenfolge in einen numerischen Typ umwandeln:
gegen
Sehr nützlich, um zu wissen, dass PowerShell immer den Typ des linken Operanden verwendet, um den endgültigen Typ eines Ausdrucks zu bestimmen, und die anzuwendenden Konvertierungen:
Dies kann helfen, zu bestimmen, wo sich unnötige Abgüsse befinden.
quelle
Vergessen Sie nicht, dass Sie nicht immer den vollständigen Namen eines Parameters angeben müssen und einige Parameter positionsabhängig sind.
... kann getrimmt werden auf ...
... weil "I" in diesem Fall ausreicht, um
InputObject
die anderen gültigen Parameter für diesen Befehl eindeutig zu identifizieren .Sie könnten es weiter trimmen, um ...
... weil
InputObject
es sich um einen Positionsparameter handelt.Piping ist normalerweise kürzer als das Zuführen von Objekten als Parameter, insbesondere wenn dadurch keine Klammern erforderlich sind. Kürzen wir unseren Zufallsgenerator weiter ...
Achten Sie auch auf andere Möglichkeiten, um das Gleiche zu erreichen, selbst wenn Sie den Befehl nicht ändern können. Für den obigen Fall könnten Sie dies tun:
Oder mit einem anderen Vorschlag *:
** Hinweis: Das Weglassen
Get-
eines Befehlsnamens kann die Laufzeit um ca. 50.000% aufblähen. Nicht schlecht, wenn Sie den Befehl nur einmal benötigen, aber seien Sie vorsichtig, wenn Sie ihn in langen Schleifen verwenden. *Und so können Sie einen einfachen Befehl auf ein Drittel seiner Größe reduzieren.
quelle
Gefälschter ternärer Operator. Sie können direkt aus einer
if
Anweisung zuweisen :Sie können jedoch ein Array mit zwei Elementen verwenden und den Test zum Indizieren verwenden. $ falsey Ergebnisse erhalten Element 0, $ truthy Ergebnisse erhalten Element 1:
NB. dass dies tut Array - Indizierung, und wenn die Testergebnisse in einem Wert wirklich die können auf eine ganze Zahl gegossen werden, werden Sie für ein Element außerhalb der Grenzen des Arrays stellen und $ null zurück und werden tun müssen ,
!(test)
um Kraft Wirf das Ergebnis in einen Bool um, wobei die Optionen umgekehrt sind.quelle
$()
. Grundsätzlich bestand ein Unterschied darin, Pipelines aus Befehlen und Anweisungen als Ausdrücke zu verwenden. Scheint mittlerweile vorbei zu sein, zumindest in PowerShell 5.Wenn Sie eine Zahl als Argument für einen Operator verwenden, für den andernfalls eine Zeichenfolge erforderlich wäre, können Sie die Zahl direkt verwenden. Vergleichen Sie
gegen
Funktioniert auch mit
-split
. Das Argument wird immer zuerst in eine Zeichenfolge konvertiert.quelle
-replace
.-replace
funktioniert auch ohne zweites Argument, wenn Sie Übereinstimmungen entfernen möchten,Absolutwert
Mit
Anstatt von
verwenden
Natürlich werden die Einsparungen storniert, wenn Klammern benötigt werden.
quelle
Wenn Sie Fehler ausschalten müssen, ist dies die naheliegende Variante
Dies ist jedoch viel zu lang. Eine kürzere Variante besteht darin, den
try
Block als Skriptblock auszuführen und die Fehler einfach in eine nicht festgelegte Variable umzuleiten ($null
wäre die übliche, aber das ist immer noch zu lang):Das spart fünf wertvolle Bytes (wenn nicht die Welt).
quelle
Verwenden Sie die
$ofs
spezielle Variable die sich ändern O utput F ield S eparator verwendet , wenn ein Array stringifying. Nützlich, wenn Sie Arrays mehrmals in Strings umwandeln müssen.Zum Beispiel:
Speichert 2+ n Zeichen auf dem 2.
-join
, wobei n die Länge des Trennzeichens ist, und speichert weitere 5+ n für das 3.-join
und jedes weitere danach.quelle
Automatische Variablen haben booleans für Wahr und Falsch , wie
$true
und$false
Sie können jedoch ähnliche Ergebnisse erhalten mit der logischen nicht Operator!
und die ganzen Zahlen 0 und 1 (oder eine ganze Zahl ungleich Null.)Nahezu alle PowerShell-Ausdrücke können als Boolesche Werte ausgewertet werden. Solange Sie wissen, wie bestimmte Daten ausgewertet werden, können Sie Boolesche Werte erhalten und müssen diese niemals explizit umwandeln. Beachten Sie dabei den LHS-Wert.
Es gibt noch andere Beispiele, aber Sie können sie einfach testen, indem Sie eine Besetzung machen
quelle
$null
falsch. Die leere Zeichenfolge (und die auf die leere Zeichenfolge festgelegten Variablen) sind falsch. Dies kann dann verwendet werden, um die Indizierung in ein Array (z. B. beim Ausführen einesif
/else
) zu verknüpfen , wie es in FizzBuzz verwendet wurde .int
s ist nur kürzerbool
. Sie können0
und1
genauso gut verwenden. Implizite Konvertierungen sind in dieser Hinsicht sehr hilfreich (die Sie häufig mit bestimmten Operatoren erzwingen können).Invoke-Expression
undGet-Random
kann anstelle von Argumenten auch eine Pipeline-Eingabe erhalten.Hierfür
iex
können Klammern für einige Ausdrücke gespeichert werden:In diesem Fall
random
kann ein allgemeiner Fall ein wenig optimiert werden:Die letztere Art der Verwendung wählt einfach ein Element aus einer Liste aus. Das
-c
Argument kann angegeben werden, um mehr als eine einzelne Auswahl zuzulassen.quelle
Ziehen Sie in Betracht, wiederholte Skriptblöcke in Variablen zu speichern, anstatt Funktionen zu verwenden.
Ich wollte dies verwenden, um einige Zeichen in meiner Rock, Paper, Scissors-Implementierung zu speichern , bevor mir klar wurde, dass das Neuschreiben der Funktion als Variable sogar die Variable unnötig machte. Dies kann jedoch für andere Skripte nützlich sein, bei denen Sie denselben Code tatsächlich mehrmals ausführen.
gegen
quelle
params(...)
würde das mehr Platz in Anspruch nehmen, als die Funktionsdefinition einspart. Verwandte: Verwenden Siefilter
über ,function
wenn Sie dies tun können.$args
, um die Notwendigkeit zu vermeidenparams
; dh$x={$args[0]+2}
(oder sogar$x={2+"$args"}
); kann unter bestimmten Umständen ein Zeichen oder 2 speichern. Sie können dies auch mit einem anderen Trick für mehrere Parameter kombinieren:$x={$a,$b=$args;$a+$b+3}
Sie können
$s|% t*y
stattdessen[char[]]$s
eine Zeichenfolge in ein char-Array aufteilen. Gegeben aus TessellatingHecklers Antwort :% t*y
expand to| ForEach-Object -Method ToCharArray
equiv. von"$args".ToCharArray()
Zum Beispiel vergleichen
und
und
Es ist besonders nützlich bei
$args
:$args|% t*y
quelle
%
Trick auch ein paar Mal für Mitglieder verwendet, aber die meisten meiner Golfspiele sind älter als dieses Feature ;-). Es ist auch eine ziemlich allgemeine Technik: Versuchen Sie, eine Buchstaben / Platzhalter-Kombination zu finden, die der Eigenschaft / Methode entspricht, die Sie benötigen (und die kürzer ist als die eigentliche).$s|% *per
für$s.toUpper()
und$s|% *wer
für$s.toLower()
. Ich bin damit einverstanden, dass das ziemlich ordentlich ist.|% t* "ddd\:hh\:mm\:ss"
für[TimeSpan].toString("ddd\:hh\:mm\:ss")
Verwenden Sie Boolesche Logik anstelle von If-Zählern in einer Schleife
Angenommen, Sie addieren alle geraden Zahlen von 1 bis 10 ...
2+4+6+8+10=30
Sie können die Boolesche Negation verwenden, um sie zu verkürzen
um ein Byte zu speichern, aber wie wäre es, wenn Sie stattdessen implizites Casting von Booleschen Zeichen für Ints verwenden und die Bedingung in den Akkumulator rollen
Spart in diesem Beispiel 6 Bytes.
quelle
Das Konvertieren von Gleitkommazahlen in Ganzzahlen in PowerShell ist ein kleines Minenfeld. Standardmäßig wird bei der Konvertierung eine Bankerrundung durchgeführt, bei der nicht immer die Dezimalstelle abgeschnitten wird und die kleinere ganze Zahl übrig bleibt, oder es wird immer auf die nächste Zahl gerundet, wie dies gelegentlich der Fall ist sei überrascht, z
und Codegolfberechnungen brechen. Viele andere gebräuchliche Sprachen runden Kürzungen ab, weshalb bei Golffragen häufig Kürzungen erforderlich sind. Sie könnten nach
[Math]::Floor()
dem nächstbesten greifen , aber beachten Sie, dass dies nur dasselbe Verhalten wie das Abschneiden von positiven Zahlen hat, aber negative Zahlen niedriger sind - weiter von Null entfernt.[Math]::Truncate()
ist das, was Sie brauchen, um das PS-Verhalten mit der Standardrundung in anderen Sprachen in Einklang zu bringen, aber es sind viele Zeichen.Durch das Ersetzen von Nachkommastellen durch Regex können einige Zeichen gespeichert werden:
quelle
Array umkehren
Erweist sich als nützlich bei vielen ASCII- Herausforderungen, bei denen die Ausgabe in gewisser Weise gespiegelt wird.
Angenommen, Sie haben
Die traditionelle Umkehrmethode ist langwierig und belässt das Array nicht für die sofortige Verwendung in der Pipeline.
Indizierung direkt in das Array in umgekehrter Reihenfolge spart einige Bytes, da die Ergebnisse in der Pipeline verbleiben, aber immer noch ziemlich lang sind:
Versuchen Sie stattdessen eine Schleife
quelle
Ab PowerShell Core 6 können Sie auch Bereiche für Zeichen verwenden:
was das viel umständlicher ersetzen kann
quelle
[char[]](65..90)
ist auch eine praktische Möglichkeit, das Alphabet zu generieren