Que dicas gerais você tem para jogar golfe no Windows PowerShell? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos do PowerShell (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.
- tirado quase literalmente da pergunta de Marcog .
code-golf
tips
powershell
Joey
fonte
fonte
Respostas:
Poderes de 10 literais com notação científica:
Poderes de 2 literais:
Pode ser útil.
fonte
Se você precisa executar um loop e sabe exatamente quantas vezes ele precisa ser executado toda vez, considere canalizar uma matriz de números inteiros contíguos
ForEach-Object
pelo%
alias em vez de usá-lofor
.for($x=1;$x-le10;$x++){
...}
vs
1..10|%{
...}
fonte
Você pode pular muito os espaços no PowerShell. Se parece que talvez não seja necessário, provavelmente não é. Isso é particularmente útil em comparações.
Exemplo:
vs.
Se você precisar ramificar seu script com base no resultado de um único teste que pode ter vários resultados,
switch
às vezes pode corresponder ou vencer uma declaração if.Exemplo (switch vs. if / else - tie):
vs.
Ou (alternar vs. if / elseif / else - alternar vence por 15):
vs.
Se o comutador for realmente baseado em determinados resultados matemáticos, como a operação do módulo acima, você poderá substituir o comutador inteiramente por uma matriz. Aqui, ele salva outros 13 caracteres e é ainda mais curto que a instrução if / else de duas opções original. (Agradecemos a Danko Durbic por esta parte.)
Se você usar muito um comando específico, especialmente um sem um apelido de mão curta pré-existente, configure um apelido de um caractere logo no início.
Exemplo:
vs.
fonte
('even','odd')[$x%2]
PARA SUA INFORMAÇÃO.Encapsular o comando que define uma variável entre parênteses permite alimentar a definição da variável diretamente para outros comandos.
Por exemplo, você pode definir $ xe, em seguida, definir $ y com base no valor de $ x de uma só vez:
Em vez disso:
Você pode definir $ h e imprimi-lo com este:
Em vez disso:
fonte
($x=New-Object Windows.Forms.Form).Controls.Add($t)
Um switch pode agir como um loop, quando recebe um array. Por exemplo:
Saída:
Não tenho muita certeza de onde isso será útil, mas espero que seja útil para alguém em algum momento.
fonte
ForEach-Object
e umswitch
dentro dele. É, por exemplo, um código (no mundo real) muito bom para escrever analisadores rápidos de arquivos de texto, nos quais é necessário fazer coisas diferentes, dependendo de qual regex corresponde uma linha.switch -File $path
é paraSubstitua
[math]::pow
por multiplicação. Ao invés devocê pode escrever
Isso funciona para expoentes inteiros> = 0.
fonte
iex
... Alias paraInvoke-Expression
Operadores de comparação trabalham em coleções de valores retornando valores correspondentes:
vai render
3
,4
e5
. Em alguns casos, isso pode ajudar a economizar um tempo maior|?{$_...}
.-match
também é um operador de comparação.fonte
1..5-gt2
Use aliases sempre que possível. Existem vários úteis:
fonte
Deseja encontrar o máximo ou o mínimo de uma coleção de valores? Tentou
ou
já?
Basta classificar e usar o último ou o primeiro item:
fonte
0
,1
,2
,3
,4
,5
,6
,7
,8
ou9
, seria salvar um byte para escrever o comprimento conhecido em vez de-1
.Encurtando nomes de propriedades
Infelizmente, diferentemente dos parâmetros, propriedades / métodos (qualquer coisa acessada com um ponto
.
) geralmente não podem ser encurtados para sua forma inequívoca.Porém, alguns cmdlets podem operar com nomes de propriedades e receber curingas, e há conjuntos de parâmetros pouco conhecidos
%
e?
que podem ser úteis.Normalmente, passamos um scriptblock e nos referimos ao item com
$_
, mas há outra forma que leva o nome de uma propriedade e ele aceita um curinga.Com uma propriedade como
.Length
não podemos usar a mágica da v3 que normalmente funcionaria em uma matriz porqueLength
é uma propriedade da própria matriz, portanto, as duas acima podem ser usadas para obter os comprimentos dos membros individuais. Oselect
vem um pouco mais curto.Mas
%
pode pegar um nome de propriedade diretamente e retornar esse valor:Que pode ser reduzido com caracteres curinga. O curinga deve ser resolvido para uma única propriedade (ou método, mais sobre isso posteriormente), para gerar um erro útil, caso contrário, indicando exatamente para quais membros ele poderia resolver.
No caso de
Length
,Le*
normalmente é o mais curto. Mesmo em uma única sequência, esse método é 1 byte menor do que apenas usar a propriedadeMas, dependendo do que você está fazendo com isso, isso pode ser pior. Você pode fazer
$a.Length*5
isso apenas com a expressão de pipeline que precisaria envolvê-la($a|% Le*)*5
; ainda pode valer a pena se for contra uma matriz, mas o ponto é que nem sempre é apropriado como uma substituição direta.Também funciona com métodos, e você pode deixar de fora o
()
que cria um nome completo com o mesmo comprimento, mas com a mesma restrição acima, às vezes tendo que envolvê-lo.O método deve ter uma sobrecarga que não requer parâmetros(você pode passar argumentos colocando-os após o nome do método, o que é muito bom):Com argumentos:
Eles não são estritamente os mesmos, pois o
-replace
operador substitui uma regex, mas se você estiver apenas substituindo uma sequência, pode (agora) ser mais curto para usar o método; ajuda que as strings sejam argumentos de cmdlet em vez de argumentos de método, para que não precisem ser citadas.Propriedades Where-Object
?
também pode usar nomes de propriedade (parciais) e aplicar um "operador" a ele (na forma de parâmetros de opção). Novamente, isso pode ser mais curto do que usar aWhere-Object
abordagem de scriptblock padrão se o nome da propriedade for suficientemente longo e exclusivo.fonte
.ToString()
!Encontrar uma soma pelo longo caminho:
Uma maneira mais curta:
E ainda mais curto:
fonte
Ponto e vírgula e quebras de linha são intercambiáveis. Código de golfe geralmente é mais legível se não estiver preso em uma única linha. E o comprimento ainda é o mesmo (desde que você use U + 000A como quebra de linha com a qual o PowerShell lida sem problemas).
fonte
O
Get
verbo está implícito. Isso pode reduzir qualquer umGet-Frob
para apenasFrob
. Os candidatos frequentes sãodate
ourandom
.Observe que isso não funcionará corretamente em alguns casos, porque você pode ter utilitários GNU em seu caminho (ou outros programas nativos que se chocam). A ordem de pesquisa de comando nesse caso parece preferir o programa nativo antes de considerar os cmdlets com os
Get-
removidos:fonte
nal g Get-Random
para salvar os caracteres mais tarde. Mudá-lo para fazernal g Random
com que o script seja interrompido indefinidamente (ou, pelo menos, leva uma quantidade excessiva de tempo para processar - não tive a paciência de esperar que ele terminasse, mas está levando várias ordens de magnitude mais longas que a forma original antes de eu abortar).Measure-Command
invocações (100 vezesGet-Random
vs.random
) me dizem que é cerca de 500 vezes mais lenta. Eu não sabia disso antes, para ser sincero. Mas é bom ter isso em mente, especialmente em loops com muitas iterações. Dito isto, o código golfed deve ser curto, não rápido ( que está sendo dito, é chato ter que esperar dois dias por uma resposta a um problema projeto Euler).Get-Variable
vs.gv
e obteve uma comparação semelhante.Get-
. É um inchaço bastante retorcido em tempo de execução, com uma economia de apenas 4 caracteres.for
os loops podem ter algo entre 0 e três instruções no cabeçalho:Loop infinito:
Loop com inicialização:
Loop com inicialização e condição final:
Nesses casos, os pontos e vírgulas adicionais no final podem ser omitidos (é explicitamente declarado na especificação da linguagem , portanto não é um detalhe de implementação) em contraste com as linguagens do tipo C, que sempre exigem exatamente três instruções.
Isso também diminui
while
um pouco. Comparare
Com o bônus adicional que você pode colocar em uma linha anterior (se houver) na
for
também sem custo extra (e até mesmo salvar um personagem).fonte
Se você estiver atribuindo uma matriz que você sabe que terá apenas dois valores, não use a indexação.
Algo assim:
Pode ser facilmente transformado em:
Isso também pode ser útil se você precisar apenas do primeiro elemento de uma matriz:
fonte
$a="apple";$o="orange"
é idêntico em comprimento. São as matrizes mais longas que às vezes podem ser otimizadas bastante bem, por exemplo, colocando todos os elementos em uma string com um separador e depois usando-split
(melhor usar espaços em branco como separador porque o unário-split
será suficiente).Transmitindo para string:
vs.
A conversão para uma string como essa também pode ser usada para achatar uma matriz de strings, em vez de uni-la:
vs.
Converter uma sequência para um tipo numérico:
vs.
Também é muito útil saber que o PowerShell sempre usa o tipo do operando esquerdo para determinar o tipo final de uma expressão e as conversões a serem aplicadas:
o que pode ajudar a determinar onde estão os elencos desnecessários.
fonte
Não esqueça que nem sempre é necessário fornecer o nome completo de um parâmetro, e alguns parâmetros são posicionais.
... pode ser aparado para ...
... porque "I", neste caso, é suficiente para identificar exclusivamente
InputObject
os outros parâmetros válidos para este comando.Você pode cortá-lo ainda mais para ...
... porque
InputObject
é um parâmetro posicional.A tubulação geralmente é mais curta do que alimentar objetos como parâmetro, especialmente quando pode remover a necessidade de parênteses. Vamos cortar ainda mais nosso gerador de números aleatórios ...
Também esteja atento a outras maneiras de realizar a mesma coisa, mesmo que você não possa alterar o comando. Para o caso acima, você pode fazer o seguinte:
Ou, incorporando outra sugestão *:
** Nota: A omissão
Get-
de um nome de comando pode aumentar o tempo de execução em cerca de 50.000%. Nada mal se você precisar do comando apenas uma vez, mas tenha cuidado ao usá-lo em loops longos. *E é assim que se pode derrubar um simples comando em um terço do seu tamanho.
fonte
Operador ternário falso. Você pode atribuir diretamente de uma
if
instrução:Mas você pode usar uma matriz de 2 elementos e usar o teste para indexá-la. Os resultados $ falsey obtêm o elemento 0, os resultados $ truthy levam o elemento 1:
NB que isso realmente está indexando a matriz e, se o teste resultar em um valor que pode ser convertido em um número inteiro, você solicitará um item fora dos limites da matriz e receberá $ null de volta, e precisará fazer isso
!(test)
para forçar converter o resultado em um bool, com as opções invertidas.fonte
$()
. Havia essencialmente uma distinção de usar pipelines feitos de comandos e instruções como expressões. Parece que está desaparecido até agora, pelo menos em PowerShell 5.Ao usar um número como argumento para um operador que, de outra forma, exigiria uma sequência, você pode usar o número diretamente. Comparar
vs.
Funciona com
-split
também. O argumento é sempre convertido em uma string primeiro.fonte
-replace
também.-replace
também funciona com nenhum segundo argumento wheb que você deseja remover as correspondências;Valor absoluto
Com
Ao invés de
usar
Obviamente, as economias são canceladas se forem necessários parênteses.
fonte
Se você precisar silenciar erros, a variante óbvia seria
No entanto, isso é muito longo. Uma variante mais curta é executar o
try
bloco como um bloco de script e apenas redirecionar os erros para uma variável não definida ($null
seria a usual, mas ainda é muito longa):Isso economiza cinco bytes valiosos (se não o mundo).
fonte
Utilizar a
$ofs
variável especial para alterar a ó utput F ield S eparator utilizado quando stringifying uma matriz. Útil se você precisar transformar matrizes em seqüências de caracteres várias vezes.Por exemplo:
Salva 2+ n caracteres no 2º
-join
, onde n é o comprimento do separador e salva 5+ n adicionais para o 3º-join
e cada um deles posteriormente.fonte
As variáveis automáticas possuem booleanos para True e False como
$true
e,$false
mas você pode obter resultados semelhantes usando o operador lógico não!
e os números inteiros 0 e 1 (ou qualquer número inteiro diferente de zero).Quase todas as expressões do PowerShell podem ser avaliadas como booleanas. Portanto, desde que você esteja ciente de como determinados dados são avaliados, é possível obter booleanos e nunca precisar convertê-los explicitamente. Esteja ciente do valor do LHS ao fazer isso.
Existem outros exemplos, mas você pode testar facilmente fazendo um elenco
fonte
$null
, que é falsey. A cadeia vazia (e as variáveis definidas para a cadeia vazia) são falsey. Etc. Isso pode ser usado para atalho a indexação em uma matriz (por exemplo, ao fazer umif
/else
), como foi usado no FizzBuzz .int
s é apenas mais curtobool
. Você pode usar0
e1
também. Conversões implícitas ajudam muito nesse aspecto (que você pode frequentemente forçar com determinados operadores).Invoke-Expression
eGet-Random
também pode obter entrada de pipeline em vez de argumentos.Para
iex
isso, permite salvar parênteses em algumas expressões:Nesse caso,
random
permite que um caso comum seja otimizado um pouco:A última maneira de usá-lo simplesmente seleciona um item de uma lista. O
-c
argumento pode ser dado para permitir mais de uma única seleção.fonte
Considere armazenar blocos de script repetidos em variáveis, em vez de usar funções.
Eu usaria isso para salvar alguns caracteres na minha implementação de Pedra, Papel e Tesoura antes de perceber que reescrever a função como uma variável tornava desnecessária a variável. No entanto, isso ainda pode ser útil para outros scripts, nos quais você está executando o mesmo código várias vezes.
vs.
fonte
params(...)
ocuparia mais espaço do que a definição de função economiza. Relacionados: Usefilter
maisfunction
quando você pode fazê-lo.$args
para evitar a necessidade deparams
; ie$x={$args[0]+2}
(ou mesmo$x={2+"$args"}
); pode salvar um personagem ou 2 em algumas circunstâncias. Você também pode combinar isso com outro truque para vários parâmetros:$x={$a,$b=$args;$a+$b+3}
Você pode usar
$s|% t*y
em vez[char[]]$s
de dividir uma string para matriz de char. Dado pela resposta de TessellatingHeckler :% t*y
expande para| ForEach-Object -Method ToCharArray
equiv. do"$args".ToCharArray()
Por exemplo, compare
e
e
É útil
$args
principalmente:$args|% t*y
fonte
%
truque para os membros algumas vezes, mas a maior parte do meu golfe é anterior a esse recurso ;-). Também é uma técnica geral: tente encontrar uma combinação de letra / curinga que corresponda à propriedade / método de que você precisa (e é mais curto que o real).$s|% *per
para$s.toUpper()
e$s|% *wer
para$s.toLower()
. Eu concordo que é muito legal.|% t* "ddd\:hh\:mm\:ss"
for[TimeSpan].toString("ddd\:hh\:mm\:ss")
Use lógica booleana no lugar de contadores if em um loop
Suponha que você esteja adicionando todos os números pares de 1 a 10 ...
2+4+6+8+10=30
Você pode usar a negação booleana para reduzi-la para
para salvar um byte, mas que tal usar a conversão implícita de booleanos para ints e rolar a condicional para o acumulador
Salva 6 bytes neste exemplo.
fonte
Converter números de ponto flutuante em números inteiros no PowerShell é um campo minado. Por padrão, a conversão faz o arredondamento de banqueiros, que nem sempre diminui o número decimal e deixa o número inteiro menor, ou sempre arredonda 0,5 para o próximo número, como as pessoas fazem casualmente; seja surpreendente, por exemplo
e quebre os cálculos do codegolf. Muitos outros idiomas comuns fazem arredondamentos de truncamento; portanto, as perguntas sobre golfe geralmente exigem truncamento. Você pode procurar
[Math]::Floor()
a próxima melhor coisa, mas cuidado, isso só se comporta da mesma forma que o truncamento para números positivos, mas diminui os números negativos - mais longe do zero.[Math]::Truncate()
é o que você precisa para alinhar o comportamento do PS ao arredondamento padrão de outro idioma, mas são muitos caracteres.Regex substituindo dígitos após o ponto decimal pode ajudar a salvar alguns caracteres:
fonte
Invertendo uma matriz
É útil em muitos desafios de arte , onde a saída é refletida de alguma maneira.
Suponha que você tenha
O método tradicional de reversão é longo, chato e não deixa a matriz no pipeline para uso imediato.
A indexação direta na matriz na ordem inversa economiza alguns bytes, pois deixa os resultados no pipeline, mas ainda é bastante longa:
Em vez disso, tente um loop
fonte
A partir do PowerShell Core 6, você também pode usar intervalos para caracteres:
que pode substituir o muito mais pesado
fonte
[char[]](65..90)
também é uma maneira útil de gerar o alfabeto