Que dicas gerais você pode dar para jogar golfe em Ruby?
Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral específicos do Ruby. (Por exemplo, "Remover comentários" não seria uma resposta.)
Poste uma dica por resposta.
Respostas:
?d
a?~
em 1.8.$><<"string"
é menor queprint"string"
.$<.map{|l|...}
será menor quewhile l=gets;...;end
. Além disso, você pode usar$<.read
para ler tudo de uma vez.$<
egets
o lerá em vez de stdin, se o nome do arquivo estiverARGV
. Assim, a maneira golfiest reimplementarcat
seria:$><<$<.read
.fonte
cat
é deixar o arquivo ruby completamente vazio (0 bytes) e insistir para que ele seja executado na linha de comando com o-p
sinalizador.puts *$<
☺
ou♫
, ou se você é louco o suficiente:?﷽.ord=65021
Use o operador splat para obter a cauda e a cabeça de uma matriz:
Isso também funciona da outra maneira:
Use o
*
método com uma string em uma matriz para unir elementos:fonte
abort
para finalizar o programa e imprimir uma sequência para STDERR - menor que oputs
seguido porexit
gets
, poderá~/$/
encontrar o comprimento (isso não conta uma nova linha à direita, se existir)[]
para verificar se uma sequência contém outra:'foo'['f'] #=> 'f'
tr
vez degsub
para substituições em caracteres:'01011'.tr('01','AB') #=> 'ABABB'
chop
vez dechomp
fonte
abort
e~/$/
~/$/
gets
, seu resultado é armazenado na$_
variável/regex/ ~= string
retorna o índice da primeira correspondência. Chamar~
um regex é equivalente a/regex/ ~= $_
. Então seria algo comos=gets;l= ~/$/
Termine o seu
end
.Tente remover
end
do seu código.Não use
def...end
para definir funções. Faça um lambda com o operador new -> no Ruby 1.9. (O operador -> é um "stabby lambda" ou "dash rocket" .) Isso economiza 5 caracteres por função.As chamadas de método são
c n
ouc(n)
. Chamadas Lambda sãoc[n]
. Alterar cada umc n
parac[n]
custar 1 caractere; portanto, se você puder usarc n
mais de 5 vezes, mantenha o método.Todos os métodos que aceitam
do...end
blocos podem aceitar{...}
blocos. Isso salva de 3 a 5 caracteres. Se a precedência de{...}
for muito alta, use parênteses para corrigi-la.Substitua
if...else...end
pelo operador ternário?:
. Se uma ramificação tiver duas ou mais instruções, coloque-as entre parênteses.Você provavelmente não possui
while
ou fazuntil
loops, mas se tiver, escreva-os no formato modificador.fonte
puts'statement 3'
necessários?Além de w0lf
Combinado com acima -> você pode torná-lo ainda mais curto
-[p]
para salvar outros 2 caracteres.fonte
Use as variáveis pré-definidas curtas sempre que possível, por exemplo, em
$*
vez deARGV
. Há uma boa lista deles aqui , junto com muitas outras informações úteis.fonte
Quando você estiver usando a interpolação de strings (como você deve ler na publicação de Martin Büttner ), você não precisará de colchetes se o seu objeto tiver um sigilo (
$
,@
) na frente. Útil para variáveis mágicas como$_
,$&
,$1
etc:Então, também, se você precisar imprimir uma variável mais do que a usa, poderá salvar alguns bytes.
fonte
Se precisar descobrir se um elemento específico
e
está dentro de um intervalor
, você pode usarem vez de mais:
ou
ou
fonte
r===e
ainda mais curto?===
implementado.$_
é a última linha de leitura.print
- se nenhum argumento fornecer conteúdo impresso de$_
~/regexp/
- abreviatura de$_=~/regexp/
No Ruby 1.8, você tem quatro métodos para
Kernel
operar$_
:chop
chomp
sub
gsub
No Ruby 1.9, esses quatro métodos existem apenas se o seu script usa
-n
or-p
.Se você deseja imprimir alguma variável frequentemente, use
trace_var(:var_name){|a|p a}
fonte
-p
ou-n
. Referência.trace_var
só funciona com $ variáveis globaisUse interpolação de string!
Para substituir
to_s
. Se você precisar de parênteses em torno do que deseja transformar em uma sequência, teráto_s
dois bytes a mais que a interpolação da sequência:Para substituir a concatenação. Se você concatenar algo cercado por duas outras strings, a interpolação poderá economizar um byte:
Também funciona se a coisa do meio for concatenada, se você apenas mover a concatenação dentro da interpolação (em vez de usar várias interpolações):
fonte
Evite
length
emif a.length<n
length
é de 6 bytes, um pouco caro no código de golfe. em muitas situações, você pode verificar se a matriz possui alguma coisa em um determinado ponto. se você passar o último índice, obteránil
um valor falsey.Então você pode mudar:
if a.length<5
aif !a[4]
para -5 bytesou
if a.length>5
aif a[5]
para -6 bytesou
if a.length<n
aif !a[n-1]
para -3 bytesou
if a.length>n
aif a[n]
para -6 bytesNota : funcionará apenas com uma matriz de todos os valores reais. ter
nil
oufalse
dentro da matriz pode causar problemas.fonte
size
... Mas isso é definitivamente melhor. BTW, funciona paraString
também.Não use as palavras
true
-false
chave e .Usar:
!p
portrue
(obrigado, histocrata!)!0
parafalse
. Se tudo o que você precisa é de um valor falso, você pode simplesmente usarp
(que retornanil
).para salvar alguns caracteres.
fonte
true
(ou seja, se um valor verdadeiro é suficiente, como em uma condição if), você nem precisa!!
.p
(que avalianil
) é um valor mais curto de falsey. O que significa que a maneira mais curta de obtertrue
é!p
.Crie matrizes usando
a=i,*a
para obtê-las na ordem inversa. Você nem precisa inicializara
, e se o fizer , não precisará ser uma matriz .fonte
Se você precisar obter um número de
ARGV
,get
ou algo semelhante para fazer algo tantas vezes, em vez de chamáto_i
-lo, basta usar?1.upto x{do something x times}
onde x é uma string.Então, usar em
?1.upto(a){}
vez dex.to_i.times{}
economizará 2 caracteres.Você também pode reescrever coisas como
p 1 while 1
oup 1 if 1
comop 1while 1
oup 1if 1
Esse exemplo não é muito útil, mas pode ser usado para outras coisas.
Além disso, se você precisar atribuir o primeiro elemento de uma matriz a uma variável,
a,=c
salvará dois caracteres em vez dea=c[0]
fonte
Novos recursos no Ruby 2.3 e 2.4
É bom ficar a par dos novos recursos de idioma que ajudarão seu jogo de golfe. Existem alguns ótimos nos últimos Rubies.
Ruby 2.3
O operador de navegação segura:
&.
Quando você chama um método que pode retornar,
nil
mas deseja encadear chamadas de método adicionais, caso contrário, desperdiça bytes manipulando onil
caso:O "operador de navegação segura" interrompe a cadeia de chamadas de método se alguém retornar
nil
e retornarnil
para toda a expressão:Array#dig
&Hash#dig
Acesso profundo a elementos aninhados, com um belo nome abreviado:
Retorna
nil
se atingir um beco sem saída:Enumerable#grep_v
O inverso de -
Enumerable#grep
retorna todos os elementos que não correspondem ao argumento fornecido (comparado com===
). Por exemplogrep
, se um bloco é fornecido, seu resultado é retornado.Hash#to_proc
Retorna um Proc que gera o valor para a chave fornecida, o que pode ser bastante útil:
Ruby 2.4
O Ruby 2.4 ainda não saiu, mas em breve estará disponível e possui alguns ótimos recursos. (Quando for lançado, atualizarei esta postagem com alguns links para os documentos.) Aprendi sobre a maioria delas nesta excelente postagem no blog .
Enumerable#sum
Não mais
arr.reduce(:+)
. Agora você pode apenas fazerarr.sum
. É necessário um argumento opcional de valor inicial, cujo padrão é 0 para elementos numéricos ([].sum == 0
). Para outros tipos, você precisará fornecer um valor inicial. Também aceita um bloco que será aplicado a cada elemento antes da adição:Integer#digits
Isso retorna uma matriz de dígitos de um número na ordem do menor para o maior:
Comparado com, digamos
123.to_s.chars.map(&:to_i).reverse
, isso é muito bom.Como bônus, é necessário um argumento radix opcional:
Comparable#clamp
Faz o que diz na lata:
Como está no Comparable, você pode usá-lo com qualquer classe que inclua Comparable, por exemplo:
String#unpack1
Economia de 2 bytes em relação a
.unpack(...)[0]
:Argumento de precisão para
Numeric#ceil
,floor
etruncate
Atribuição múltipla em condicionais
Isso gera um erro nas versões anteriores do Ruby, mas é permitido na 2.4.
fonte
Math::E.ceil(1)
paraMath::E.ceil 1
, e da mesma forma parafloor
etruncate
.Enumerable#sum
,.flatten.sum
é 2 bytes menor que.sum{|a,b|a+b}
(-Math::E).truncate(1)
é equivalente ao-Math::E.truncate(1)
que é 1 byte mais curto&.
pode ser usado com subscrições como essaa&.[]i
(1 byte menor quea&.at i
). Embora, se forem necessários colchetes,a||a[i]
1 byte é menor quea&.[](i)
oua&.at(i)
A notação científica geralmente pode ser usada para cortar um ou dois caracteres:
fonte
1e2
é melhor do que100.0
quando uma porcentagem é necessária.1.0*
é 1 caractere mais curto que.to_f
Use métodos de operador em vez de parênteses
Digamos que você queira se expressar
a*(b+c)
. Por causa da precedência,a*b+c
não funcionará (obviamente). A maneira legal de Ruby de ter operadores como métodos vem em socorro! Você pode usara.*b+c
para tornar a precedência*
menor que a de+
.Isso também pode funcionar com os operadores
!
e~
(coisas como unárias+
ou unárias-
não funcionam porque seus métodos são-@
e+@
, salvando()
mas adicionando.@
)fonte
Use
||
em vez dissoor
e&&
em vez dissoand
.Ao lado de um caractere,
and
você pode salvar os espaços (e talvez o suporte) ao redor do operador.Se você faz um loop em uma matriz, você normalmente usa
each
. Masmap
também faz um loop em uma matriz e é um caractere mais curto.fonte
Eu apenas tentei um desafio de código-golfe no TDD, ou seja, escreva o código mais curto para fazer as especificações passarem. As especificações eram algo como
Por uma questão de código-golfe, não é necessário criar um módulo ou classe.
Ao invés de
alguém pode fazer
Salva 13 caracteres!
fonte
PigLatin
, mas também para@pig_latin
,$pig_latin
, e'pig'['latin']
.translate
foi definido emnil
.O kernel # p é um método divertido.
Use em
p var
vez deputs var
. Isso funciona perfeitamente com números inteiros e flutuantes, mas não com todos os tipos. Ele imprime aspas em torno de strings, o que provavelmente não é o que você deseja.Usado com um único argumento,
p
retorna o argumento após imprimi-lo.Usado com vários argumentos,
p
retorna os argumentos em uma matriz.Use
p
(sem argumentos) em vez denil
.fonte
p 'some string'
imprime"some string"
e não apenas osome string
que é frequentemente criticado por outros.p s
é o mesmo queputs s.inspect
, mas ele retornas
Não use #each. Você pode fazer um loop sobre todos os elementos muito bem com #map. Então, ao invés de
você pode fazer o mesmo em menos bytes.
Obviamente, nesse caso,
puts $*
seria ainda mais curto.Existem literais para números racionais e complexos:
Você pode usar a maioria dos bytes dentro de strings.
"\x01"
(6 bytes) pode ser reduzido para""
(3 bytes). Se você precisar apenas desse byte, ele poderá ser reduzido ainda mais para?
(2 bytes).Da mesma forma, você pode obter novas linhas mais curtas assim:
Você pode usar
?\n
e?\t
bem, que é um byte menor do que"\n"
e"\t"
. Para ofuscação, também há um espaço.Use constantes em vez de passar argumentos, mesmo que precise alterá-los. O intérprete dará avisos ao stderr , mas quem se importa. Se você precisar definir mais variáveis relacionadas entre si, poderá encadeá-las da seguinte maneira:
Isso é mais curto que
C=9;B=16;A=17
ouC=0;B=C+7;A=C+B
.Se você precisar de um loop infinito, use
loop{...}
. Loops de comprimento desconhecido podem ser mais curtos com outros loops:Mais alguns truques gsub / regexp. Use os
'\1'
caracteres de escape especiais em vez de um bloco:E as variáveis especiais
$1
etc., se você precisar executar operações. Lembre-se de que eles são definidos não apenas dentro do bloco:Livre-se de espaços, novas linhas e parênteses. Você pode omitir um pouco o rubi. Em caso de dúvida, tente sempre se funciona sem problemas e lembre-se de que isso pode interromper a sintaxe de alguns editores que destacam ...
fonte
?\n
é legal, mas não muito mais curto do que realmente colocar um caractere de nova linha entre aspas. (mesmo para guia)puts$*
é ainda mais curto.x+=1;$*<<A
Ainda outra maneira de usar o operador splat: se você deseja atribuir uma única matriz literal, a
*
no lado esquerdo é mais curta que os colchetes no lado direito:Com vários valores, você nem precisa do operador splat (obrigado ao histocrat por me corrigir nisso):
fonte
Quando um desafio exige que você produza várias linhas, você não precisa repetir os resultados para imprimir cada linha, por exemplo, uma matriz. O
puts
método achatará uma matriz e imprimirá cada elemento em uma linha separada.A combinação do operador splat com
#p
você pode torná-lo ainda mais curto:O operador splat (tecnicamente, o
*@
método, eu acho) também lança seus enumeráveis não array para matrizes:vs
fonte
*@
não é um método, splat é açúcar sintáticoSalve alguns bytes ao remover elementos repetidos de uma matriz
Se você estiver usando uma matriz vazia
[]
em uma variável, poderá salvar ainda mais bytes:fonte
a&a
é 1 byte mais curtoUse Goruby em vez de Ruby, que é algo como uma versão abreviada do Ruby. Você pode instalá-lo com o rvm via
O Goruby permite que você escreva a maior parte do seu código como escreveria Ruby, mas possui abreviações adicionais. Para descobrir a abreviação mais curta disponível para algo, você pode usar o método auxiliar
shortest_abbreviation
, por exemplo:Também é muito útil o alias
say
para oputs
qual ele próprio pode ser abreviados
. Então, ao invés deagora você pode escrever
para imprimir o alfabeto em maiúsculas (o que não é um bom exemplo). Esta postagem do blog explica mais coisas e alguns dos trabalhos internos, se você estiver interessado em ler mais.
PS: não perca o
h
método ;-)fonte
Para ingressar em uma matriz, em vez desta
fazem isto
que economiza 2 bytes. Para ingressar em um separador, use
fonte
Números de assinatura!
Acabei de descobrir isso ontem.
n[i]
retornan
o bit nai
posição-th. Exemplo:fonte
n[0..3]
Você pode salvar 2 caracteres e usar
ao invés de
Por exemplo, suponha que tenhamos um intervalo que queremos como uma matriz:
Apenas faça assim:
E agora você tem seu alcance como uma matriz.
fonte
[*1..2000]
funciona também?<< truque
pode ser reduzido para:
para -4 bytes.
fonte
String
sArray#assoc
/rassoc
Quando você tem uma matriz de matrizes e deseja encontrar a sub-matriz que começa com um valor específico, não use
Enumerable#find
, useArray#assoc
:Este também é um bom substituto para
Enumerable#any?
em algumas situações.Array#rassoc
faz a mesma coisa, mas verifica o último elemento das sub-matrizes:fonte
a.any?
linha dorassoc
exemplo, o que|x,|
faz? Qual é a diferença|x|
?x=[1,2]
vsx,=[1,2]
. Usando o meu exemplo acima, com|x|
, na primeira iteraçãox
será[0,"foo"]
. Com|x,y|
,x
será0
ey
será"foo"
. Da mesma forma, com|x,|
,x
será0
. Em outras palavras, ele diz que "colocar o primeiro elementox
e jogar o resto fora.|,y|
é um SyntaxError, ergo|_,y|
. Mas agora percebi que|*,y|
funciona, o que é mais limpo do que usar uma variável chamada_
(mas não menor).