¿Qué consejos generales tiene para jugar al golf en Windows PowerShell? Estoy buscando ideas que puedan aplicarse a los problemas de golf de código en general que sean al menos algo específicos de PowerShell (por ejemplo, "eliminar comentarios" no es una respuesta). Por favor, publique un consejo por respuesta.
Tomado casi al pie de la letra de la pregunta de Marcog .
code-golf
tips
powershell
Joey
fuente
fuente
Respuestas:
Potencias de 10 literales con notación científica:
Poderes de 2 literales:
Podría ser útil.
fuente
Si necesita ejecutar un bucle y sabe exactamente cuántas veces necesita ejecutarse cada vez, considere conectar una matriz de enteros contiguos a
ForEach-Object
través del%
alias en lugar de usarfor
.for($x=1;$x-le10;$x++){
...}
vs
1..10|%{
...}
fuente
Puede omitir muchos espacios en PowerShell. Si parece que podría no ser necesario, posiblemente no lo sea. Esto es particularmente útil en las comparaciones.
Ejemplo:
vs.
Si necesita bifurcar su script en función del resultado de una sola prueba que puede tener múltiples resultados, a
switch
veces puede igualar o superar una declaración if.Ejemplo (cambio vs. if / else - empate):
vs.
O (cambiar vs if / elseif / else - cambiar gana por 15):
vs.
Si el interruptor se basa realmente en ciertos resultados matemáticos, como la operación de módulo anterior, puede reemplazar el interruptor por completo con una matriz. Aquí, guarda otros 13 caracteres y es incluso más corto que la declaración original de dos opciones if / else. (Gracias a Danko Durbic por esta parte).
Si va a utilizar mucho un comando en particular, especialmente uno sin un alias de mano corta preexistente, configure un alias de un solo carácter desde el principio.
Ejemplo:
vs.
fuente
('even','odd')[$x%2]
FYI.Encapsular el comando que define una variable entre paréntesis le permite alimentar la definición de la variable directamente a otros comandos.
Por ejemplo, puede establecer $ x y luego establecer $ y en función del valor de $ x en una sola toma con esto:
En lugar de esto:
Puede configurar $ h y generarlo con esto:
En lugar de esto:
fuente
($x=New-Object Windows.Forms.Form).Controls.Add($t)
Un interruptor puede actuar como un bucle, cuando se le da una matriz. Por ejemplo:
Saldrá:
No estoy totalmente seguro de dónde será útil, pero espero que sea útil para alguien en algún momento.
fuente
ForEach-Object
y unswitch
dentro de eso. Es, por ejemplo, un código (en el mundo real) muy bueno para escribir analizadores rápidos de archivos de texto en los que debe hacer cosas diferentes dependiendo de la expresión regular de una línea.switch -File $path
esReemplazar
[math]::pow
con multiplicación. En lugar depuedes escribir
Esto funciona para exponentes enteros> = 0.
fuente
iex
... Alias paraInvoke-Expression
Los operadores de comparación trabajan en colecciones de valores devolviendo valores coincidentes:
cederá
3
,4
y5
. En algunos casos, esto puede ayudar a ahorrar un tiempo más largo|?{$_...}
.-match
es un operador de comparación también.fuente
1..5-gt2
Use alias siempre que sea posible. Hay un montón de útiles:
fuente
¿Quiere encontrar el máximo o mínimo de una colección de valores? Intentó
o
¿ya?
Simplemente ordene y use el último o primer elemento:
fuente
0
,1
,2
,3
,4
,5
,6
,7
,8
o9
, se ahorraría un byte para escribir la longitud conocida en lugar de-1
.Acortar nombres de propiedad
Lamentablemente, a diferencia de los parámetros, las propiedades / métodos (todo lo que se accede con un punto
.
) no se pueden acortar a su forma inequívoca.Pero ciertos cmdlets pueden operar con nombres de propiedad y tomar comodines, y hay conjuntos de parámetros poco conocidos
%
y?
que pueden ser útiles.Por lo general, pasamos un bloque de script y nos referimos al elemento con
$_
, pero hay otra forma de estos que toma un nombre de propiedad y acepta un comodín.Con una propiedad como
.Length
no podemos usar la magia v3 que normalmente funcionaría en una matriz porqueLength
es una propiedad de la matriz en sí misma, por lo que las dos anteriores podrían usarse para obtener las longitudes de los miembros individuales. Elselect
viene en un poco más corto.Pero
%
puede tomar un nombre de propiedad directamente y devolver ese valor:Que se puede acortar con comodines. El comodín debe resolverse en una sola propiedad (o método, más sobre eso más adelante), por lo que arrojará un error útil si no lo hace, indicando exactamente a qué miembros podría resolver.
En el caso de
Length
,Le*
suele ser el más corto. Incluso en una sola cadena, este método es 1 byte más corto que simplemente usar la propiedad.Pero dependiendo de lo que esté haciendo con esto, esto puede ser peor. Puede hacerlo,
$a.Length*5
pero para hacerlo con la expresión de canalización, tendría que ajustarlo($a|% Le*)*5
; aún podría valer la pena si está en contra de una matriz, pero el punto es que no siempre es apropiado como una sustitución directa.También funciona con métodos, y puede omitir el
()
que hace que un nombre completo tenga la misma longitud, pero la misma restricción que antes, sobre a veces tener que envolverlo.El método debe tener una sobrecarga que no tome parámetros(puede pasar argumentos colocándolos después del nombre del método, lo cual es realmente bueno):Con argumentos:
Estos no son estrictamente iguales en el sentido de que el
-replace
operador hace un reemplazo de expresiones regulares, pero si solo está haciendo un reemplazo de cadena, puede (ahora) ser más corto para usar el método; ayuda que las cadenas sean argumentos de cmdlet en lugar de argumentos de método, por lo que no es necesario citarlas.Propiedades del objeto donde
?
también puede tomar nombres de propiedades (parciales) y aplicarle un "operador" (en forma de parámetros de cambio). Nuevamente, esto puede ser más corto que usar elWhere-Object
enfoque estándar de bloque de script si el nombre de la propiedad es lo suficientemente largo y único.fuente
.ToString()
!Encontrar una suma a lo largo del camino:
Un camino más corto:
Y aún más corto:
fuente
Los punto y coma y los saltos de línea son intercambiables. El código de golf es a menudo más legible si no se atasca en una sola línea. Y la longitud sigue siendo la misma (siempre que use U + 000A como salto de línea que PowerShell maneja sin problemas).
fuente
El
Get
verbo está implícito. Esto puede acortar cualquieraGet-Frob
a soloFrob
. Los contendientes frecuentes sondate
orandom
.Tenga en cuenta que esto no funcionará correctamente en algunos casos porque puede tener utilidades GNU en su camino (u otros programas nativos que entren en conflicto). La búsqueda de orden de comando en ese caso parece preferir el programa nativo antes de considerar cmdlets con el
Get-
eliminado:fuente
nal g Get-Random
guardar caracteres más adelante. Cambiarlo anal g Random
causa que el script se cuelgue indefinidamente (o, al menos, tome un tiempo excesivo para procesarlo; no he tenido la paciencia de esperar a que termine, pero está tomando varios órdenes de magnitud más que la forma original antes de abortar).Measure-Command
invocaciones cortas (100 vecesGet-Random
vs.random
) me dicen que es aproximadamente 500 veces más lento. No lo sabía antes, para ser honesto. Pero es bueno tenerlo en cuenta, especialmente en bucles con muchas iteraciones. Dicho esto, el código de golf debe ser corto, no rápido ( dicho esto, apesta tener que esperar dos días para obtener una respuesta a un problema del Proyecto Euler).Get-Variable
vs.gv
y obtuve una comparación similar.Get-
. Esa es una hinchazón bastante retorcida en el tiempo de ejecución para un ahorro de solo 4 caracteres de longitud.for
los bucles pueden tener entre 0 y tres declaraciones en su encabezado:Ciclo infinito:
Bucle con inicialización:
Bucle con inicialización y condición final:
En tales casos, se pueden omitir los puntos y comas adicionales al final (se indica explícitamente en la especificación del lenguaje , por lo que no es un detalle de implementación) en contraste con los lenguajes tipo C que siempre requieren exactamente tres declaraciones.
Esto también hace
while
un poco más corto. Comparary
Con la bonificación adicional de que puedes quedarte en una línea anterior (si hay una) en el
for
también sin costo adicional (e incluso guardar un personaje).fuente
Si está asignando una matriz que sabe que solo tendrá dos valores, no use la indexación.
Algo como esto:
Se puede convertir fácilmente en esto:
Esto también puede ser útil si solo necesita el primer elemento de una matriz:
fuente
$a="apple";$o="orange"
es idéntico en longitud. Son las matrices más largas las que a veces se pueden optimizar bastante bien, por ejemplo, colocando todos los elementos en una cadena con un separador y luego usando-split
(lo mejor es usar espacios en blanco como separador porque entonces el unario-split
será suficiente).Fundición a cuerda:
vs.
La conversión a una cadena como esta también se puede usar para aplanar una serie de cadenas, en lugar de unirla:
vs.
Transmitir una cadena a un tipo numérico:
vs.
También es muy útil saber que PowerShell siempre toma el tipo del operando izquierdo para determinar el tipo final de una expresión y las conversiones a aplicar:
lo que puede ayudar a determinar dónde están los moldes innecesarios.
fuente
No olvide que no siempre necesita proporcionar el nombre completo de un parámetro, y algunos parámetros son posicionales.
... se puede recortar para ...
... porque "I", en este caso, es suficiente para identificar de manera única
InputObject
los otros parámetros válidos para este comando.Podrías recortarlo aún más para ...
... porque
InputObject
es un parámetro posicional.La tubería suele ser más corta que alimentar objetos como parámetro, especialmente cuando puede eliminar la necesidad de paréntesis. Recortemos más nuestro generador de números aleatorios ...
También esté atento a otras formas de lograr lo mismo, incluso si no puede cambiar el comando. Para el caso anterior, puede hacer esto:
O, incorporando otra sugerencia *:
** Nota: La omisión
Get-
de un nombre de comando puede aumentar el tiempo de ejecución en aproximadamente un 50,000%. No está mal si solo necesita el comando una vez, pero tenga cuidado al usarlo en bucles largos. *Y así es como puede derribar un comando simple hasta un tercio de su tamaño.
fuente
Operador ternario falso. Puede asignar directamente desde una
if
declaración:Pero puede usar una matriz de 2 elementos y usar la prueba para indexarla. Los resultados de $ falsey obtienen el elemento 0, los resultados de $ verdadero toman el elemento 1:
NÓTESE BIEN. que esto realmente está haciendo indexación de matriz, y si la prueba da como resultado un valor que se puede convertir a un entero, solicitará un elemento fuera de los límites de la matriz y obtendrá $ nulo de regreso, y tendrá que hacerlo
!(test)
para forzar lanzar el resultado a un bool, con las opciones invertidas.fuente
$()
. Hubo esencialmente una distinción del uso de tuberías hechas de comandos y declaraciones como expresiones. Parece que ya no existe, al menos en PowerShell 5.Cuando use un número como argumento para un operador que de otra manera requeriría una cadena, puede usar el número directamente. Comparar
vs.
Funciona con
-split
también. El argumento siempre se convierte primero en una cadena.fuente
-replace
.-replace
también funciona sin un segundo argumento cuando quiera eliminar coincidencias,Valor absoluto
Con
En lugar de
utilizar
Por supuesto, los ahorros se cancelan si se necesitan paréntesis.
fuente
Si necesita silenciar los errores, la variante obvia sería
Sin embargo, esto es demasiado largo. Una variante más corta es ejecutar el
try
bloque como un bloque de script y simplemente redirigir los errores a una variable no establecida ($null
sería la habitual, pero aún es demasiado larga):Esto ahorra cinco bytes valiosos (si no el mundo).
fuente
Utilice la
$ofs
variable especial para cambiar el O utput F ield S eparator utilizado cuando stringifying una matriz. Útil si necesita transformar matrices en cadenas varias veces.Por ejemplo:
Guarda 2+ n caracteres en el 2do
-join
, donde n es la longitud del separador, y guarda 5+ n adicionales para el 3ro-join
y cada uno a partir de entonces.fuente
Las variables automáticas tienen booleanos para Verdadero y Falso como
$true
y,$false
pero puede obtener resultados similares utilizando el operador lógico no!
y los enteros 0 y 1 (o cualquier entero distinto de cero).Casi todas las expresiones de PowerShell se pueden evaluar como booleanos. Por lo tanto, siempre que sepa cómo se evalúan ciertos datos, puede obtener booleanos y nunca necesitará emitirlos explícitamente. Tenga en cuenta el valor de LHS al hacer esto.
Hay otros ejemplos, pero puedes probarlos fácilmente haciendo un reparto
fuente
$null
, falsey. La cadena vacía (y las variables establecidas en la cadena vacía) son falsey. Etc. Esto se puede usar para atajar la indexación en una matriz (por ejemplo, al hacer unif
/else
), como se usó en FizzBuzz .int
s es más cortobool
. Puedes usar0
y1
igual de bien. Las conversiones implícitas ayudan mucho en ese sentido (que a menudo puede forzar con ciertos operadores).Invoke-Expression
yGet-Random
también puede obtener entradas de canalización en lugar de argumentos.Para
iex
esto permite guardar paréntesis en algunas expresiones:En caso de que
random
esto permita que un caso común se optimice un poco:La última forma de usarlo simplemente selecciona un elemento de una lista. Se
-c
puede dar el argumento para permitir más de una sola selección.fuente
Considere almacenar bloques de script repetidos en variables, en lugar de usar funciones.
Iba a usar esto para guardar algunos caracteres en mi implementación de Piedra, Papel, Tijera antes de darme cuenta de que reescribir la función como una variable hacía innecesaria incluso la variable. Sin embargo, esto podría ser útil para otras secuencias de comandos, donde realmente está ejecutando el mismo código varias veces.
vs.
fuente
params(...)
, ocuparía más espacio del que guarda la definición de función. Relacionado: Usofilter
sobrefunction
cuándo puede hacerlo.$args
para evitar la necesidad deparams
; es decir$x={$args[0]+2}
(o incluso$x={2+"$args"}
); puede guardar un personaje o 2 en algunas circunstancias. También puede combinar esto con otro truco para múltiples parámetros:$x={$a,$b=$args;$a+$b+3}
En su
$s|% t*y
lugar, puede usar[char[]]$s
para dividir una cadena en una matriz de caracteres. Dado de la respuesta de TessellatingHeckler : se% t*y
expande a| ForEach-Object -Method ToCharArray
equiv. de"$args".ToCharArray()
Por ejemplo, compare
y
y
Es útil
$args
especialmente con :$args|% t*y
fuente
%
truco para miembros varias veces, pero la mayoría de mis juegos de golf son anteriores a esa característica ;-). También es una técnica bastante general: intente encontrar una combinación de letra / comodín que coincida con la propiedad / método que necesita (y es más corta que la real).$s|% *per
por$s.toUpper()
y$s|% *wer
para$s.toLower()
. Estoy de acuerdo en que es bastante bueno.|% t* "ddd\:hh\:mm\:ss"
para[TimeSpan].toString("ddd\:hh\:mm\:ss")
Utilice la lógica booleana en lugar de los contadores de if en un bucle
Supongamos que está agregando todos los números pares del 1 al 10 ...
2+4+6+8+10=30
Podría usar la negación booleana para acortarla a
para guardar un byte, pero ¿qué tal si en su lugar utiliza la conversión implícita de booleanos a ints y pasa el condicional al acumulador?
Guarda 6 bytes en este ejemplo.
fuente
La conversión de números de punto flotante a enteros en PowerShell es un poco un campo minado. Por defecto, la conversión realiza redondeo de los banqueros, que no siempre recorta el decimal y deja el número entero más pequeño, o siempre redondea .5 al siguiente número, como lo hace la gente de manera casual, redondea los pares de una manera y las probabilidades de otra manera, esto puede ser sorprendente, por ejemplo
y romper los cálculos de codegolf. Muchos otros idiomas comunes hacen redondeo de truncamiento, por lo tanto, las preguntas de golf a menudo requieren truncamiento. Puede llegar a
[Math]::Floor()
ser la siguiente mejor opción, pero tenga en cuenta que esto solo se comporta igual que el truncamiento para números positivos, pero toma números negativos más bajos, más lejos de cero.[Math]::Truncate()
es lo que necesita para alinear el comportamiento de PS con el redondeo predeterminado de otro idioma, pero son muchos caracteres.Regex reemplazando dígitos después del punto decimal puede ayudar a guardar un par de caracteres:
fuente
Invertir una matriz
Resulta útil en muchos desafíos de ascii-art donde la producción se refleja de alguna manera.
Supongamos que tienes
El método de inversión tradicional es largo, aburrido y no deja la matriz en la tubería para su uso inmediato.
La indexación directamente en la matriz en orden inverso ahorra algunos bytes, ya que deja los resultados en la tubería, pero aún es bastante largo:
En cambio, intente un bucle
fuente
A partir de PowerShell Core 6, también puede usar rangos para caracteres:
que puede reemplazar a los mucho más engorrosos
fuente
[char[]](65..90)
también es una forma práctica de generar el alfabeto