Quels conseils généraux avez-vous pour jouer au golf dans Windows PowerShell? Je recherche des idées pouvant être appliquées aux problèmes de code de golf en général, qui sont au moins quelque peu spécifiques à PowerShell (par exemple, "supprimer les commentaires" n'est pas une réponse). Merci de poster un pourboire par réponse.
... pris presque textuellement de la question de Marcog .
code-golf
tips
powershell
Joey
la source
la source
Réponses:
Pouvoirs de 10 littéraux avec notation scientifique:
Pouvoirs de 2 littéraux:
Pourrait être utile.
la source
Si vous devez exécuter une boucle et que vous savez exactement combien de fois elle doit être exécutée à chaque fois, envisagez de canaliser un tableau d'entiers contigus
ForEach-Object
via l'%
alias au lieu d'utiliserfor
.for($x=1;$x-le10;$x++){
...}
contre
1..10|%{
...}
la source
Vous pouvez beaucoup ignorer les espaces dans PowerShell. Si vous sentez que cela n’est peut-être pas nécessaire, ce n’est peut-être pas le cas. Ceci est particulièrement utile dans les comparaisons.
Exemple:
contre.
Si vous devez créer une branche dans votre script en fonction du résultat d'un test unique pouvant avoir plusieurs résultats, vous
switch
pouvez parfois associer ou surpasser une instruction if.Exemple (commutateur vs. if / else - tie):
contre.
Ou (commutateur vs si / elseif / else - commutateur gagne par 15):
contre.
Si le commutateur est réellement basé sur certains résultats mathématiques, comme l'opération modulo ci-dessus, vous pouvez le remplacer entièrement par un tableau. Ici, il enregistre 13 caractères supplémentaires et est même plus court que l’instruction originale if / else à deux options. (Merci à Danko Durbic pour ce bit.)
Si vous utilisez beaucoup une commande particulière, en particulier une sans alias abrégé préexistant, définissez un alias à caractère unique au début.
Exemple:
contre.
la source
('even','odd')[$x%2]
FYI.L'encapsulation de la commande qui définit une variable entre parenthèses vous permet de transmettre la définition de la variable directement à d'autres commandes.
Par exemple, vous pouvez définir $ x, puis $ y en fonction de la valeur de $ x d'un coup avec ceci:
Au lieu de cela:
Vous pouvez définir $ h et le sortir avec ceci:
Au lieu de cela:
la source
($x=New-Object Windows.Forms.Form).Controls.Add($t)
Un commutateur peut agir comme une boucle quand on lui donne un tableau. Par exemple:
Est-ce que la sortie:
Je ne suis pas tout à fait sûr de savoir où cela sera utile, mais je m'attends à ce que ce soit utile pour quelqu'un quelque temps.
la source
ForEach-Object
et de l'switch
intérieur. Par exemple (dans le monde réel), le code est très utile pour écrire des analyseurs rapides de fichiers texte dans lesquels vous devez faire différentes choses en fonction de la regex avec laquelle une ligne correspond.switch -File $path
pourRemplacez
[math]::pow
par la multiplication. Au lieu detu peux écrire
Cela fonctionne pour les exposants entiers> = 0.
la source
iex
... Alias pourInvoke-Expression
Les opérateurs de comparaison travaillent sur des collections de valeurs en renvoyant des valeurs correspondantes:
va céder
3
,4
et5
. Dans certains cas, cela peut aider à économiser plus longtemps|?{$_...}
.-match
est aussi un opérateur de comparaison.la source
1..5-gt2
Utilisez des alias autant que possible. Il y a un tas d'utiles:
la source
Vous voulez trouver le maximum ou le minimum d'une collection de valeurs? A tenté
ou
déjà?
Il suffit de trier et d'utiliser le dernier ou le premier élément:
la source
0
,1
,2
,3
,4
,5
,6
,7
,8
ou9
, il sauverait un octet pour écrire la longueur connue au lieu de-1
.Raccourcir les noms de propriété
Malheureusement, contrairement aux paramètres, les propriétés / méthodes (tout ce qui est accédé par un point
.
) ne peuvent généralement pas être réduites à leur forme non ambiguë.Mais certaines cmdlets peuvent opérer sur les noms de propriété et prendre des caractères génériques, et il existe des ensembles de paramètres peu connus de
%
et?
qui peuvent être utiles.Habituellement, nous transmettons un bloc de script et faisons référence à l'élément avec
$_
, mais il existe une autre forme de ceux-ci qui prend un nom de propriété et accepte un caractère générique.Avec une propriété comme celle-ci,
.Length
nous ne pouvons pas utiliser la magie v3 qui fonctionnerait normalement sur un tableau car ilLength
s'agit d'une propriété du tableau lui-même. Les deux propriétés ci-dessus peuvent donc être utilisées pour obtenir les longueurs des membres individuels. Leselect
vient dans un peu plus court.Mais
%
peut prendre directement un nom de propriété et renvoyer cette valeur:Ce qui peut être raccourci avec des jokers. Le caractère générique doit être résolu en une seule propriété (ou méthode, à ce sujet plus tard), de sorte qu'il générera une erreur utile s'il ne le fait pas, indiquant exactement quels membres il pourrait résoudre.
Dans le cas de
Length
,Le*
est généralement le plus court. Même sur une seule chaîne, cette méthode est plus courte d'un octet que la simple utilisation de la propriété.Mais selon ce que vous faites avec cela, cela peut être pire. Vous pouvez le faire,
$a.Length*5
mais pour le faire avec l'expression du pipeline, vous devez l'envelopper($a|% Le*)*5
; Cela peut toujours valoir la peine si cela est contre un tableau, mais le fait est que ce n’est pas toujours approprié comme substitution directe.Cela fonctionne aussi avec les méthodes, et vous pouvez laisser le
()
nom complet de la même longueur, mais les mêmes restrictions que ci-dessus concernant le fait de devoir l’emballer.La méthode doit avoir une surcharge qui ne prend aucun paramètre(vous pouvez passer des arguments en les plaçant après le nom de la méthode, ce qui est très pratique):Avec des arguments:
Ce ne sont pas strictement les mêmes en ce que le
-replace
opérateur effectue un remplacement d'expression régulière, mais si vous remplacez simplement une chaîne, il peut (maintenant) être plus court pour utiliser la méthode; il est utile que les chaînes soient des arguments d'applets de commande plutôt que des arguments de méthodes, de sorte qu'elles n'ont pas besoin d'être citées.Propriétés Where-Object
?
peut également prendre des noms de propriété (partiels) et y appliquer un "opérateur" (sous la forme de paramètres de commutateur). Là encore, cela peut être plus court que d'utiliser l'Where-Object
approche scriptblock standard si le nom de la propriété est suffisamment long et unique.la source
.ToString()
!Trouver une somme sur le long chemin:
Un moyen plus court:
Et même plus court:
la source
Les points-virgules et les sauts de ligne sont interchangeables. Le code de golf est souvent plus lisible s’il n’est pas inséré dans une seule ligne. Et la longueur est toujours la même (à condition que vous utilisiez U + 000A comme saut de ligne que PowerShell gère sans problèmes).
la source
Le
Get
verbe est impliqué. Cela peut raccourcir toutGet-Frob
à justeFrob
. Les prétendants fréquents sontdate
ourandom
.Notez que cela ne fonctionnera pas correctement dans certains cas car vous pourriez avoir des utilitaires GNU dans votre chemin (ou d’autres programmes natifs qui s’entrechoquent). Dans ce cas, l'ordre de recherche semble préférer le programme natif avant qu'il ne considère les cmdlets avec les éléments
Get-
supprimés:la source
nal g Get-Random
sauvegarder les personnages plus tard. En le changeant ennal g Random
changez en, le script se bloque indéfiniment (ou, du moins, prend un temps démesuré à traiter - je n'ai pas eu la patience d'attendre la fin, mais cela prend plusieurs ordres de grandeur plus longtemps que la forme d'origine. avant d’avorter).Measure-Command
invocations courtes (100 foisGet-Random
contrerandom
) me disent que c'est environ 500 fois plus lent. Pour être honnête, je ne le savais pas auparavant. Mais il est bon de garder cela à l'esprit, en particulier dans les boucles avec de nombreuses itérations. Cela étant dit, le code golfé devrait être court, pas rapide ( cela dit, ça craint de devoir attendre deux jours pour obtenir une réponse à un problème de Project Euler).Get-Variable
contregv
et obtenu une comparaison similaire.Get-
. Il s’agit là d’un assez lourd gonflement en temps d’exécution pour une économie de seulement 4 caractères.for
Les boucles peuvent avoir n'importe quoi entre 0 et trois déclarations dans leur en-tête:Boucle sans fin:
Boucle avec initialisation:
Boucle avec initialisation et condition de fin:
Dans de tels cas, les points-virgules supplémentaires à la fin peuvent être omis (c'est explicitement indiqué dans la spécification du langage). , il ne s'agit donc pas d'un détail d'implémentation), contrairement aux langages de type C qui exigent toujours exactement trois instructions.
Cela fait aussi
while
un peu plus court. Compareret
Avec le bonus supplémentaire que vous pouvez coller dans une ligne précédente (s'il en existe une) dans le
for
aussi bien sans frais supplémentaires (et même en sauvant un personnage).la source
Si vous assignez un tableau dont vous savez qu'il n'aura que deux valeurs, n'utilisez pas d'indexation.
Quelque chose comme ça:
Peut facilement être transformé en ceci:
Cela peut aussi être utile si vous avez juste besoin du premier élément d'un tableau:
la source
$a="apple";$o="orange"
est de longueur identique. Ce sont les tableaux les plus longs qui peuvent parfois être assez bien optimisés, par exemple en plaçant tous les éléments dans une chaîne avec un séparateur, puis en utilisant-split
(il est préférable d’utiliser (utiliser l’espace comme séparateur, car alors le unaire-split
suffira).Casting à la chaîne:
contre.
La conversion en chaîne de cette manière peut également être utilisée pour aplatir un tableau de chaînes au lieu de le joindre:
contre.
Conversion d'une chaîne en un type numérique:
contre.
Il est également très utile de savoir que PowerShell utilise toujours le type de l'opérande gauche pour déterminer le type final d'une expression et les conversions à appliquer:
ce qui peut aider à déterminer où se trouvent les moulages inutiles.
la source
N'oubliez pas que vous n'avez pas toujours besoin de fournir le nom complet d'un paramètre. Certains paramètres sont positionnels.
... peut être coupé pour ...
... parce que "I", dans ce cas, est suffisant pour identifier
InputObject
de manière unique les autres paramètres valides pour cette commande.Vous pouvez le couper plus loin pour ...
... car
InputObject
est un paramètre de position.La tuyauterie est généralement plus courte que l'alimentation d'objets en tant que paramètre, en particulier lorsqu'elle peut supprimer le besoin de parenthèse. Coupons encore plus notre générateur de nombres aléatoires ...
Recherchez également d’autres moyens d’accomplir la même chose, même si vous ne pouvez pas modifier la commande. Pour le cas ci-dessus, vous pouvez faire ceci:
Ou, incorporant une autre suggestion *:
** Remarque: L'omission
Get-
d'un nom de commande peut alourdir le temps d'exécution d'environ 50 000%. Pas mal si vous n’avez besoin que de la commande une fois, mais faites attention de ne pas l’utiliser avec de longues boucles. *Et c’est comme cela que l’on peut faire tomber une simple commande au tiers de sa taille.
la source
Faux opérateur ternaire. Vous pouvez attribuer directement à partir d'une
if
déclaration:Mais vous pouvez utiliser un tableau à 2 éléments et utiliser le test pour y indexer. Les résultats de $ falsey reçoivent l'élément 0, les résultats de la vérité $ prennent l'élément 1:
NB qu'il s'agisse bien d'une indexation sur un tableau, et si le test donne une valeur pouvant être convertie en un entier, vous demanderez un élément situé en dehors des limites du tableau et obtiendrez $ null en retour, et vous devrez le faire
!(test)
pour forcer jette le résultat dans un bool, avec les options inversées.la source
$()
. Il existait essentiellement une distinction entre l'utilisation de pipelines à partir de commandes et d'instructions en tant qu'expressions. On dirait que cela a déjà été fait, du moins dans PowerShell 5.Lorsque vous utilisez un nombre en tant qu'argument d'un opérateur qui nécessiterait sinon une chaîne, vous pouvez utiliser le nombre directement. Comparer
contre.
Fonctionne avec
-split
aussi bien. L'argument est toujours d'abord converti en chaîne.la source
-replace
aussi bien.-replace
fonctionne également sans deuxième argument lorsque vous souhaitez supprimer des allumettes,Valeur absolue
Avec
Au lieu de
utilisation
Bien entendu, les économies sont annulées si des parenthèses sont nécessaires.
la source
Si vous devez faire taire les erreurs, la variante évidente serait
Cependant, c'est beaucoup trop long. Une variante plus courte consiste à exécuter le
try
bloc en tant que bloc de script et à rediriger simplement les erreurs dans une variable non définie (ce$null
serait la variable habituelle, mais celle-ci est encore trop longue):Cela économise cinq précieux octets (si ce n'est le monde).
la source
Utiliser la
$ofs
variable spéciale pour changer le O utput F ield S eparator utilisé lorsque stringifying un tableau. Utile si vous devez transformer des tableaux en chaînes plusieurs fois.Par exemple:
Enregistre 2 + n caractères sur le 2e
-join
, où n est la longueur du séparateur, et enregistre 5 + n supplémentaires pour le 3e-join
et ensuite.la source
Les variables automatiques ont des booléens pour True et False au fur
$true
et à mesure ,$false
mais vous pouvez obtenir des résultats similaires en utilisant l'opérateur non logique!
et les entiers 0 et 1 (ou tout autre entier non nul.)Presque toutes les expressions PowerShell peuvent être évaluées en tant que booléens. Donc, tant que vous savez comment certaines données sont évaluées, vous pouvez obtenir des booléens sans jamais avoir besoin de les diffuser explicitement. Soyez conscient de la valeur LHS lorsque vous effectuez ces opérations.
Il y a d'autres exemples mais vous pouvez facilement tester en faisant un casting
la source
$null
sont Falsey. La chaîne vide (et les variables définies sur la chaîne vide) sont falsey. Etc. Ceci peut ensuite être utilisé pour raccourcir l'indexation dans un tableau (par exemple, lors de l' exécution d' unif
/else
), comme c'était le cas dans FizzBuzz .int
s est juste plus courtebool
. Vous pouvez utiliser0
et1
tout aussi bien. Les conversions implicites aident beaucoup à cet égard (que vous pouvez souvent forcer avec certains opérateurs).Invoke-Expression
etGet-Random
peut également obtenir une entrée de pipeline au lieu d'arguments.Pour
iex
cela permet d'enregistrer entre parenthèses sur certaines expressions:Dans le cas
random
contraire, cela permet d’optimiser un peu le cas commun:Cette dernière façon de l'utiliser sélectionne simplement un élément dans une liste. L'
-c
argument peut être donné pour permettre plus d'une sélection.la source
Envisagez de stocker des blocs de script répétés dans des variables, au lieu d'utiliser des fonctions.
J'allais l'utiliser pour enregistrer des caractères dans mon implémentation Rock, Paper, Scissors avant de réaliser que réécrire la fonction sous forme de variable rendait même la variable inutile. Cela pourrait néanmoins être utile pour d’autres scripts, où vous exécutez le même code plusieurs fois.
contre.
la source
params(...)
cela prend plus de place que la définition de fonction n'enregistre. Connexes: Utilisezfilter
plusfunction
quand vous pouvez le faire.$args
pour éviter le besoin deparams
; c'est-à-dire$x={$args[0]+2}
(ou même$x={2+"$args"}
); peut sauver un personnage ou 2 dans certaines circonstances. Vous pouvez également combiner cela avec une autre astuce pour plusieurs paramètres:$x={$a,$b=$args;$a+$b+3}
Vous pouvez utiliser à la
$s|% t*y
place[char[]]$s
pour diviser une chaîne en tableau de caractères. D'après la réponse de TessellatingHeckler :% t*y
étend à| ForEach-Object -Method ToCharArray
équiv. de"$args".ToCharArray()
Par exemple, comparez
et
et
C'est utile avec
$args
surtout:$args|% t*y
la source
%
truc pour les membres plusieurs fois, mais la plupart de mes golfs sont antérieurs à cette caractéristique ;-). C'est aussi une technique assez générale: essayez de trouver une combinaison lettre / caractère générique qui corresponde à la propriété / méthode dont vous avez besoin (et qui est plus courte que la réalité).$s|% *per
pour$s.toUpper()
et$s|% *wer
pour$s.toLower()
. Je suis d'accord que c'est assez chouette.|% t* "ddd\:hh\:mm\:ss"
pour[TimeSpan].toString("ddd\:hh\:mm\:ss")
Utiliser la logique booléenne à la place des if-counters dans une boucle
Supposons que vous ajoutiez tous les nombres pairs de 1 à 10 ...
2+4+6+8+10=30
Vous pouvez utiliser la négation booléenne pour la raccourcir à
pour sauvegarder un octet, mais que diriez-vous d'utiliser plutôt le transtypage implicite de Booléens en entiers, et d'insérer le conditionnel dans l'accumulateur
Enregistre 6 octets dans cet exemple.
la source
La conversion de nombres à virgule flottante en nombres entiers dans PowerShell est un peu un champ de mines. Par défaut, la conversion arrondit les banquiers, ce qui ne coupe pas toujours la décimale et ne laisse pas le nombre entier le plus petit, ou arrondit toujours le chiffre 5 au chiffre suivant, comme cela se fait de façon décontractée, elle arrondit même l’un dans l’autre et l’autre avec un autre être surprenant, par exemple
et briser les calculs de code-golf. De nombreux autres langages courants effectuent des arrondissements par troncature, c'est pourquoi les questions de golf nécessitent souvent une troncature. Vous pourriez atteindre pour
[Math]::Floor()
meilleure chose à faire peut-être, mais attention, cela ne se comporte que de la même manière que la troncature pour les nombres positifs, mais que les nombres négatifs sont plus bas - plus loin de zéro.[Math]::Truncate()
C’est ce dont vous avez besoin pour aligner le comportement de PS sur les arrondis par défaut des autres langues, mais il faut beaucoup de caractères.Le remplacement des chiffres par une expression régulière après la virgule décimale peut vous aider à enregistrer quelques caractères:
la source
Inverser un tableau
Est utile dans beaucoup de défis artistiques où la sortie est reflétée d'une manière ou d'une autre.
Supposons que vous ayez
La méthode d'inversion traditionnelle est longue, ennuyeuse et ne laisse pas la matrice sur le pipeline pour une utilisation immédiate.
L'indexation directe dans le tableau en ordre inverse économise quelques octets, car les résultats sont conservés dans le pipeline, mais restent assez longs:
Au lieu de cela, essayez une boucle
la source
À partir de PowerShell Core 6, vous pouvez également utiliser des plages pour les caractères:
qui peut remplacer le beaucoup plus lourd
la source
[char[]](65..90)
est également un moyen pratique de générer l'alphabet