Tipps zum Golfen in PowerShell

45

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 .

Joey
quelle
3
Als ich "PowerShell Golf" gegoogelt habe, war dies der erste Hit!
Matt

Antworten:

24

Potenzen von 10 Literalen mit wissenschaftlicher Notation:

4e6 = 4000000

Potenzen von 2 Litern:

4KB = 4096
4MB = 4194304
4GB = 4294967296

# TB and PB suffixes also exist, but less useful for golf.

Könnte sich als nützlich erweisen.

Joey
quelle
19

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 verwenden for.

for($x=1;$x-le10;$x++){...}

vs

1..10|%{...}

Iszi
quelle
18

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:

$x-eq$i-and$x-ne9

gegen

$x -eq $i -and $x -ne 9

Wenn Sie Ihr Skript basierend auf dem Ergebnis eines einzelnen Tests verzweigen müssen, der mehrere Ergebnisse haben switchkann , kann eine if-Anweisung manchmal übereinstimmen oder übertroffen werden.

Beispiel (switch vs. if / else - tie):

if($x%2-eq0){'even'}else{'odd'}

gegen

switch($x%2){0{'even'}1{'odd'}}

Oder (switch vs. if / elseif / else - switch gewinnt mit 15):

if($x%2-eq0){'even'}elseif($x%2-eq1){'odd'}else{'error'}

gegen

switch($x%2){0{'even'}1{'odd'}2{'error'}}

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.)

('even','odd','error')[$x%2]

Wenn Sie einen bestimmten Befehl häufig verwenden, insbesondere einen Befehl ohne bereits vorhandenen Kurznamen, richten Sie frühzeitig einen Einzelzeichen-Alias ​​ein.

Beispiel:

nal g Get-Random;g 10;g 10;g 10

gegen

Get-Random 10;Get-Random 10;Get-Random 10
Iszi
quelle
('even','odd')[$x%2]Zu Ihrer Information.
TheIncorrigible1
15

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:

$y=($x=1)+1

An Stelle von:

$x=1;$y=$x+1

Du kannst $ h setzen und damit ausgeben:

($h='Hello World!')

An Stelle von:

$h='Hello World!';$h
Iszi
quelle
1
Dies ist besonders nützlich, um Methoden für Objekte aufzurufen. ($x=New-Object Windows.Forms.Form).Controls.Add($t)
Rechtschreibung
14

Ein Switch kann sich wie eine Schleife verhalten, wenn er ein Array erhält. Zum Beispiel:

$FooBarMeh='a','b','c'
switch ($FooBarMeh)
{
    'a'{'FOO'}
    'b'{'BAR'}
    default{'MEH'}
}

Wird ausgeben:

FOO
BAR
MEH

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.

Iszi
quelle
2
Es ist praktisch, jedes Mal, wenn Sie ein ForEach-Objectund ein switchin 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.
Joey
Das ist ... verdammt komisch. Ein Array sollte nicht mit einem Zeichen übereinstimmen, tut es aber.
Katze
@ Joey Das ist, was switch -File $pathist für
TheIncorrigible1
Nicht alles, was analysiert wird, ist eine Datei.
Joey
12

Durch [math]::powMultiplikation ersetzen . Anstatt von

[math]::pow($a,$b)

Du kannst schreiben

"$a*"*$b+1|iex

Dies funktioniert für ganzzahlige Exponenten> = 0.

Danko Durbić
quelle
Ich musste diese Antwort sehen, um zu verstehen iex... Alias ​​fürInvoke-Expression
HeatfanJohn
11

Vergleichsoperatoren bearbeiten Wertesammlungen, indem sie übereinstimmende Werte zurückgeben:

1..5 -gt 2

wird ergeben 3, 4und 5. In einigen Fällen kann dies dazu beitragen, eine ansonsten längere Zeit zu sparen |?{$_...}.

-match ist auch ein Vergleichsoperator.

Joey
quelle
1
Beachten Sie, dass Sie in diesem Beispiel keine Leerzeichen benötigen1..5-gt2
Matt
1
Ich weiß; Hier ging es mehr darum, die Technik zu zeigen. Leerzeichen stehen in einer separaten Antwort .
Joey
11

Verwenden Sie nach Möglichkeit Aliase. Es gibt eine Reihe von nützlichen:

?        Where-Object
%        ForEach-Object
gu       Get-Unique
sort     Sort-Object
iex      Invoke-Expression
Joey
quelle
11

Möchten Sie das Maximum oder Minimum einer Wertesammlung ermitteln? Versucht

(...|measure -ma).Maximum

oder

(...|measure -mi).Minimum

bereits?

Einfach sortieren und den letzten oder ersten Artikel verwenden:

(...|sort)[-1]  # maximum
(...|sort)[0]   # minimum
Joey
quelle
1
Und wenn Sie die Länge der
Wertesammlung kennen
@ wizzwizz4: Oh, maximale Längen können oft kreativ eingesetzt werden, nicht unbedingt 10. Obwohl ich mich für diesen speziellen Fall nicht an eine Instanz erinnere, bei der es jemals geholfen hat.
Joey
1
Ich meine, wenn das letzte Element zu sein , ist bekannt 0, 1, 2, 3, 4, 5, 6, 7, 8oder 9wäre es ein Byte speichert die bekannte Länge statt zu schreiben -1.
wizzwizz4
10

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.

$o|select Le*  
$o|%{$_.Length}

Mit einer Eigenschaft wie der können .Lengthwir nicht die v3-Magie verwenden, die normalerweise für ein Array funktioniert, da Lengthes 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. Das selectkommt etwas kürzer rein.

Aber %kann einen Eigenschaftsnamen nehmen direkt und zurück , dass Wert:

$a|% Length

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.

$a.Length                # 9   #(doesn't work on array)
$a|%{$_.Length}          # 15
$a|% Le*                 # 8

Aber je nachdem, was Sie damit machen, kann es schlimmer sein. Sie können dies $a.Length*5nur 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):

$a.ToUpper()             # 12
$a|% *per                #  9

Mit Argumenten:

'gaga'-replace'g','r'    # 21
'gaga'|% *ce g r         # 16

Dies ist nicht unbedingt dasselbe, da der -replaceOperator 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-ObjectScriptblock-Ansatzes, wenn der Eigenschaftsname lang und eindeutig genug ist.

$a|?{$_.Length-gt5}      # 19
$a|? Le* -GT 5           # 14

($a|% Le*)-gt5           # 14 - Lengths, not objs
Briantist
quelle
1
Einer der wenigen Orte, an denen Leerzeichen erforderlich sind. Netter Fund. Ich kann mir mehrere Bereiche vorstellen, in denen dies die Dinge verkürzen wird.
AdmBorkBork
Nice edit Joey! Vielen Dank.
Briantist
Hab dir einen Weg gefunden, es kürzer zu machen ;-) ... das Traurige daran ist, dass es sich insgesamt wieder um eine Pipeline handelt, die den Nutzen ein wenig einschränkt. Oder vielmehr, es gibt viele Stellen, an denen Sie es erneut in Klammern setzen müssen, um einen Ausdruck zu erhalten. Aber nur wenige
Joey
1
@ConnorLSW ah ja, ich wollte dies aktualisieren, da ich seitdem erkannt habe, dass Sie Argumente auf diese Weise übergeben können, was die Nützlichkeit erheblich steigert. Gute Verwendung von .ToString()!
Briantist
2
@briantist dies hat PowerShell zu einer viel wettbewerbsfähigeren Sprache gemacht, die einige der nervig wortreichen .Net-Aufrufe wirklich ausschließt.
Colsw
9

Auf dem langen Weg eine Summe finden:

(...|measure -s).Sum

Ein kürzerer Weg:

...|%{$s+=$_};$s

Und noch kürzer:

...-join'+'|iex
Joey
quelle
9

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).

Joey
quelle
2
Warten Sie, wir sind besorgt über die Lesbarkeit ?!
Kevin Cox
4
Wenn es keinen Einfluss auf die Länge hat ... warum nicht?
Joey
Macht es technisch keinen Unterschied, da ein Semikolon ein Zeichen weniger als \ r \ n ist? Nur in Unix ist es ein Singular \ n.
Vasili Syrakis
2
@ Vasili: Sie können die Dateien ganz gut mit nur U + 000A zwischen den Zeilen speichern. PowerShell beschwert sich nicht. Was ich übrigens schon in der Antwort geschrieben habe. Zeilenumbrüche sind eine Eigenschaft der Datei und nicht des Betriebssystems, auf dem sie verwendet werden. Niemand sagt, dass Sie unter Windows keine Unix-Zeilenenden verwenden können.
Joey
@Joey Wenn Sie eine Neuinstallation von Windows verwendet haben, um eine schnelle Programmierung durchzuführen, werden Sie feststellen, dass Notepad nicht gut mit \ x0a
Stan Strum
9

Das GetVerb ist impliziert. Das kann man beliebig Get-Frobauf gerade verkürzen Frob. Häufige Konkurrenten sind dateoder random.

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:

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
Joey
quelle
Dies gilt nicht ganz immer funktionieren wie erwartet. Ich habe ein Skript, nal g Get-Randomdas später mit dem Speichern von Zeichen beginnt . Wenn Sie es auf nal 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).
Iszi
2
Zwei kurze Measure-CommandAufrufe (100 Mal Get-Randomvs. 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).
Joey
1
Mein Problem bestand darin, 10.000 Iterationen des Monty Hall-Szenarios auszuführen, für die jeweils drei Iterationen von Get-Random erforderlich waren. Eine um 50.000% längere Bearbeitungszeit, multipliziert mit 30.000 Durchläufen, ist ziemlich unangenehm.
Iszi
Beeindruckend. Es sieht so aus, als ob das Gleiche wahrscheinlich für jeden Alias ​​gilt. Getestet Get-Variablegegen gvund bekam einen ähnlichen Vergleich.
Iszi
1
Das könnte es sein. Ich habe ein bisschen nachgerechnet und mein Monty Hall-Skript sollte ungefähr 1,5 Stunden (normalerweise 10-11 Sekunden) dauern, ohne es auszuführen Get-. Das ist eine ziemlich aufgedunsene Laufzeit bei einer Ersparnis von nur 4 Zeichen Länge.
Iszi
8

for Schleifen können zwischen 0 und drei Anweisungen im Header haben:

Endlosschleife:

for(){}

Schleife mit Initialisierung:

for($n=0){}

Schleife mit Initialisierungs- und Endebedingung:

for($n=0;$n-lt7){}

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 whileein bisschen kürzer. Vergleichen Sie

while(...){}

und

for(;...){}

Mit dem zusätzlichen Bonus, dass Sie in einer vorherigen Zeile (falls vorhanden) forauch ohne zusätzliche Kosten (und sogar Speichern eines Charakters) bleiben können .

Joey
quelle
8

Wenn Sie ein Array zuweisen, von dem Sie wissen, dass es nur zwei Werte enthält, verwenden Sie keine Indizierung.

Etwas wie das:

$a="apple","orange"
$a[0] # apple
$a[1] # orange

Kann leicht in diese umgewandelt werden:

$a,$o="apple","orange"
$a # apple
$o # orange

Dies kann auch nützlich sein, wenn Sie nur das erste Element eines Arrays benötigen:

$a,$b=1..10
$a # 1
$b # 2..10
SomeShinyObject
quelle
In diesem Fall (mit den Saiten) $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 -splitausreicht).
Joey
8

Casting zum String:

[string]$x

gegen

"$x"

Das Umwandeln in einen String wie diesen kann auch verwendet werden, um ein Array von Strings zu reduzieren, anstatt sie zu verbinden:

$a = @('a','b','c')
$a -join ' '

gegen

$a = @('a','b','c')
"$a"

Zeichenfolge in einen numerischen Typ umwandeln:

[int]$x     [float]$x

gegen

+$x

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:

'1'+2    -> '12'
1+'2'    -> 3

Dies kann helfen, zu bestimmen, wo sich unnötige Abgüsse befinden.

Joey
quelle
6

Vergessen Sie nicht, dass Sie nicht immer den vollständigen Namen eines Parameters angeben müssen und einige Parameter positionsabhängig sind.

Get-Random -InputObject (0..10)

... kann getrimmt werden auf ...

Get-Random -I (0..10)

... weil "I" in diesem Fall ausreicht, um InputObjectdie anderen gültigen Parameter für diesen Befehl eindeutig zu identifizieren .

Sie könnten es weiter trimmen, um ...

Get-Random (0..10)

... weil InputObjectes 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 ...

0..10|Get-Random

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:

Get-Random 11

Oder mit einem anderen Vorschlag *:

Random 11

** 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.

Iszi
quelle
6

Gefälschter ternärer Operator. Sie können direkt aus einer ifAnweisung zuweisen :

$z=if($x-eq$y){"truth"}else{"false"}

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:

$z=("false","true")[$x-eq$y]

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.

TessellatingHeckler
quelle
Das erste Snippet hat zu einem bestimmten Zeitpunkt nicht funktioniert (ältere PowerShell-Versionen) $(). 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.
Joey,
Wenn die Array-Elemente nicht statisch sind, werden beide als Teil der Array-Erstellung analysiert und verarbeitet, bevor die Indizierung erfolgt und das Ergebnis zugewiesen wird. Zum Beispiel .
AdmBorkBork
6

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

...-join'0'

gegen

...-join0

Funktioniert auch mit -split. Das Argument wird immer zuerst in eine Zeichenfolge konvertiert.

Joey
quelle
Als Referenz funktioniert dies auch mit -replace.
AdmBorkBork
-replacefunktioniert auch ohne zweites Argument, wenn Sie Übereinstimmungen entfernen möchten,
Joey
5

Absolutwert

Mit

$n=-123

Anstatt von

[math]::abs($n)

verwenden

$n-replace'-'

Natürlich werden die Einsparungen storniert, wenn Klammern benötigt werden.

Rynant
quelle
Oder wenn Sie das Ergebnis auf der linken Seite eines Operators benötigen ;-)
Joey
5

Wenn Sie Fehler ausschalten müssen, ist dies die naheliegende Variante

try{ <# something that throws errors #> }catch{}

Dies ist jedoch viel zu lang. Eine kürzere Variante besteht darin, den tryBlock als Skriptblock auszuführen und die Fehler einfach in eine nicht festgelegte Variable umzuleiten ( $nullwäre die übliche, aber das ist immer noch zu lang):

.{ <# something that throws errors #> }2>$x

Das spart fünf wertvolle Bytes (wenn nicht die Welt).

Joey
quelle
5

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:

$a=1,2,3,4
$a-join',';$a-join','
$ofs=',';"$a";"$a"

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. -joinund jedes weitere danach.

AdmBorkBork
quelle
1
Leider sehr selten nützlich (zumindest in meinem bisherigen Golfspiel - ich neige dazu, es am Ende auf nur eine einzige Verbindung zu reduzieren).
Joey
5

Automatische Variablen haben booleans für Wahr und Falsch , wie $trueund $falseSie können jedoch ähnliche Ergebnisse erhalten mit der logischen nicht Operator !und die ganzen Zahlen 0 und 1 (oder eine ganze Zahl ungleich Null.)

PS C:\Users\matt> !1
False

PS C:\Users\matt> !0
True

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.

  • Ganzzahl 0 ist falsch und Ganzzahlen ungleich Null werden mit wahr bewertet.
  • Zeichenfolgen mit einer Länge ungleich Null sind wahr und leer, oder Zeichenfolgen mit einer Länge ungleich Null (und Nullen selbst) sind falsch.

Es gibt noch andere Beispiele, aber Sie können sie einfach testen, indem Sie eine Besetzung machen

PS C:\Users\matt> [bool]@(0)
False
Matt
quelle
1
Viele andere Datentypen haben ebenfalls einen ähnlichen Status. Nicht initialisierte Variablen sind standardmäßig $nullfalsch. 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 eines if/ else) zu verknüpfen , wie es in FizzBuzz verwendet wurde .
AdmBorkBork
@TimmyD Sehr wahr. Mit ints ist nur kürzer
Matt
@TimmyD Ich wollte Fizzbuzz beantworten, bis ich deins sah .... Kann das nicht schlagen .... zumindest noch nicht
Matt
Beachten Sie, dass in vielen Fällen Sie nicht wirklich brauchen ein bool. Sie können 0und 1genauso gut verwenden. Implizite Konvertierungen sind in dieser Hinsicht sehr hilfreich (die Sie häufig mit bestimmten Operatoren erzwingen können).
Joey
4

Invoke-Expressionund Get-Randomkann anstelle von Argumenten auch eine Pipeline-Eingabe erhalten.

Hierfür iexkönnen Klammern für einige Ausdrücke gespeichert werden:

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

In diesem Fall randomkann ein allgemeiner Fall ein wenig optimiert werden:

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

Die letztere Art der Verwendung wählt einfach ein Element aus einer Liste aus. Das -cArgument kann angegeben werden, um mehr als eine einzelne Auswahl zuzulassen.

Joey
quelle
4

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.

function Hi{echo 'Hello, World!'};Hi

gegen

$Hi={echo 'Hello, World!'};&$Hi
Iszi
quelle
2
Nützlich für Funktionen, die keine Argumente annehmen. Andernfalls params(...)würde das mehr Platz in Anspruch nehmen, als die Funktionsdefinition einspart. Verwandte: Verwenden Sie filterüber , functionwenn Sie dies tun können.
Joey
Sie könnten verwenden $args, um die Notwendigkeit zu vermeiden params; 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}
JohnLBevan
4

Sie können $s|% t*ystattdessen [char[]]$seine Zeichenfolge in ein char-Array aufteilen. Gegeben aus TessellatingHecklers Antwort : % t*yexpand to | ForEach-Object -Method ToCharArrayequiv. von"$args".ToCharArray()

Zum Beispiel vergleichen

$s|% t*y

und

[char[]]$s

und

$s.ToCharArray()

Es ist besonders nützlich bei $args:$args|% t*y

mazzy
quelle
1
Das ist ganz ordentlich. Ich habe den %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).
Joey
Weitere nützliche Beispiele aus der Antwort: $s|% *perfür $s.toUpper()und $s|% *werfür $s.toLower(). Ich bin damit einverstanden, dass das ziemlich ordentlich ist.
mazzy
Ein weiteres Beispiel : |% t* "ddd\:hh\:mm\:ss"für[TimeSpan].toString("ddd\:hh\:mm\:ss")
mazzy
Nun, das ist also nur eine Verschwendung von Zitaten. du brauchst sie hier nicht :-)
Joey
3

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

1..10|%{if($_%2-eq0){$o+=$_}};$o

Sie können die Boolesche Negation verwenden, um sie zu verkürzen

1..10|%{if(!($_%2)){$o+=$_}};$o

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

1..10|%{$o+=$_*!($_%2)};$o

Spart in diesem Beispiel 6 Bytes.

AdmBorkBork
quelle
2
Jesus Christus. Ich plane, dies in meinem Produktionscode bei der Arbeit zu tun, meine Kollegen werden mich dafür lieben.
Chavez
3

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

PS C:\> [int]1.5
2

PS C:\> [int]2.5
2

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:

[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
TessellatingHeckler
quelle
3

Array umkehren

Erweist sich als nützlich bei vielen Herausforderungen, bei denen die Ausgabe in gewisser Weise gespiegelt wird.

Angenommen, Sie haben

$a=1,2,3,4,5

Die traditionelle Umkehrmethode ist langwierig und belässt das Array nicht für die sofortige Verwendung in der Pipeline.

[array]::reverse($a)

Indizierung direkt in das Array in umgekehrter Reihenfolge spart einige Bytes, da die Ergebnisse in der Pipeline verbleiben, aber immer noch ziemlich lang sind:

$a[($a.count-1)..0]

Versuchen Sie stattdessen eine Schleife

$a|%{$a[-++$i]}
AdmBorkBork
quelle
Die umgekehrte Indizierung funktioniert gut, wenn es eine Obergrenze für die Zählung gibt
Joey,
3

Ab PowerShell Core 6 können Sie auch Bereiche für Zeichen verwenden:

'a'..'z'

was das viel umständlicher ersetzen kann

0..25|%{[char]($_+97)}
Joey
quelle
Oh, das wird so praktisch sein.
AdmBorkBork
1
[char[]](65..90)ist auch eine praktische Möglichkeit, das Alphabet zu generieren
Veskah