Respostas:
As dicas abaixo variam do mais econômico ao mais usado:
Use os comandos de alto nível do Mathematica sempre que possível, mesmo os volumosos:
MorphologicalComponents: Código-Golfe: Count Islands
Recursos de manipulação de imagem: por exemplo, hoje (24 de setembro) é o aniversário da HONDA
Subsets
IntegerPartitions
Medidas de distância e semelhança: por exemplo, EuclideanDistancepode ser um economizador de bytes. Observe, no entanto, que geralmente é mais curto escrever em Total@Abs[a-b]vez de a~ManhattanDistance~be em Max@Abs[a-b]vez de a~ChessboardDistance~b.
Use Graphics and Textpara arte Ascii: por exemplo, programação em estrela!
e construa um relógio analógico
Símbolos dedicados:
símbolos de operações lógicas e de conjunto em vez de seus nomes longos: ⋂, ⋃, ∧, ∨
Mape Apply: /@, //@. @@,@@@
Notação de prefixo e infixo:
Print@"hello" no lugar de Print["hello"]
a~f~b no lugar de f[a,b]
Quando uma função é usada apenas uma vez, uma função pura pode economizar um ou dois caracteres.
Juntando seqüências de caracteres em uma lista. ""<>{"a","b","c"}ao invés deStringJoin@{"a","b","c"}
Explorar funções listáveis. Quanto mais longas as listas, melhor.
{a, b, c} + {x, y, z}= {a+x, b+y, c+z}
{2, 3, 4} {5, 6, 7}= {10, 18, 28}
{{a, b}, {c, d}}^{2, 3} = {{a^2, b^2}, {c^3, d^3}}
Algumas funções internas com nomes longos podem ser substituídas por expressões mais curtas.
Por exemplo:
Total => TrTranspose=> Threadou\[Transpose]True => 1<2False => 1>2Times => 1##&Alternatives => $|##&IntegerQ => ⌊#⌋==#&a[[1]] => #&@@aa[[All,1]] => #&@@@aConstantArray[a,n]=> Array[a&,n]ouTable[a,{n}]Union@a=> {}⋃aoua⋃aToExpression@n=> FromDigits@nse né um númeroDivisible[n,m] => m∣nFromDigits[n,2]=> Fold[#+##&,n]Se né uma lista de 0s e 1sComplex@z=> {1,I}.zonde zestá uma lista do formulário{x,y}Thread[{{a,b},{c,d}}]== Thread[List[{a,b},{c,d}]]== {List[a,c],List[b,d]}== {{a,c},{b,d}}==Transpose[{{a,b},{c,d}}]
Foldtruque FromDigitstambém funciona para qualquer outra base, exceto 10. Por exemplo FromDigits[n,5]-> Fold[4#+##&,n](com o bônus de salvar um byte extra para bases 100e 1000).
U+F3C7.
Echoseja uma opção, porque ela imprime >>(e um espaço) em STDOUT antes de imprimir a string real.
Complex[x,y] => {1,I}.{x,y}, eu acho que x+y*Ié muito mais curto com o mesmo efeito?
Este é um vetor bastante comum para se trabalhar:
{0,0}
Acontece que isso pode ser reduzido por um byte:
0{,}
Ainda mais bytes são salvos se o vetor for maior que dois zeros. Isso também pode ser usado para inicializar matrizes zero, por exemplo, o seguinte fornece uma matriz 2x2 de zeros:
0{{,},{,}}
Isso também pode ser usado para valores diferentes de zero se forem suficientemente grandes ou muitos ou negativos. Compare os seguintes pares:
{100,100}
0{,}+100
{-1,-1}
0{,}-1
{3,3,3,3}
0{,,,}+3
Mas lembre-se de que, a partir de 6 valores, você estará melhor 1~Table~6nesse caso (potencialmente mais cedo, dependendo dos requisitos de precedência).
A razão pela qual isso funciona é que ,introduz dois argumentos na lista, mas argumentos omitidos (em qualquer lugar do Mathematica) são implícitos Null. Além disso, a multiplicação é Listablee 0*xé 0para quase todos x(exceto para coisas como Infinitye Indeterminate), então aqui está o que está acontecendo:
0{,}
= 0*{,}
= 0*{Null,Null}
= {0*Null,0*Null}
= {0,0}
Para listas de 1s, você pode usar um truque semelhante usando regras de exponenciação. Existem duas maneiras diferentes de salvar bytes, se você tiver pelo menos três 1s na lista:
{1,1,1}
1^{,,}
{,,}^0
1^{,,,}é um byte menor que 0{,,,}+1.
{,,}^0. Eu vou editar a postagem.
Ao jogar código no golfe, você costuma empregar uma abordagem funcional, na qual usa funções anônimas (puras) com a &sintaxe abreviada. Existem várias maneiras diferentes de acessar os argumentos de uma função e, geralmente, você pode economizar alguns bytes tendo uma boa noção das possibilidades.
Você provavelmente sabe disso se já usou funções puras antes. O n º argumento é referido como #n, e #atua como um alias para #1. Portanto, se, digamos, você quiser escrever uma função que tome como parâmetros outra função e seu argumento (para passar o argumento para essa função), use
#@#2&
Isso não funciona com números negativos (como você pode usar ao acessar listas).
Um dos principais recursos novos de linguagem do Mathematica 10 é o Associations, que são basicamente mapas de valores-chave com tipos de chave arbitrários, escritos como
<| x -> 1, "abc" -> 2, 5 -> 3 |>
Se essa associação for passada como o primeiro argumento para uma função pura, você poderá acessar alguns se os argumentos forem parâmetros nomeados:
{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)
Observe que #ainda se refere a toda a associação conforme o esperado. Para que os parâmetros nomeados funcionem, as chaves devem ser cadeias de caracteres (não funcionará se você usar variáveis indefinidas, por exemplo), e essas cadeias devem começar com uma letra e conter apenas letras e dígitos.
#0Um recurso menos conhecido é que #0também existe e fornece o próprio objeto de função. Isso pode ser realmente útil em quines e em generalizados. De fato, o menor quine Mathematica (eu sei) é
ToString[#0][] & []
O que é um pouco chato é que ele não fornece os caracteres exatos digitados. Por exemplo, se usado @para aplicação de função, ele ainda será renderizado [...]e espaços serão inseridos em alguns lugares. Isso normalmente tornará o quine um pouco mais longo do que você gostaria, mas sempre funcionará, jogando o quine primeiro e depois apenas copiando sua saída - que agora deve ser um quine real.
Além de quines, isso também significa que você pode escrever código recursivo sem precisar nomear sua função. Compare estas três implementações de Fibonacci (ingênuas, mas eficientes):
f@0=0;f@1=1;f@n_:=f[n-1]+f[n-2]
f@n_:=If[n<2,n,f[n-1]+f[n-2]]
If[#<2,#,#0[#-1]+#0[#-2]]&
Agora é aqui que a mágica real começa. As seqüências não são usadas frequentemente no golfe, porque Sequenceé um nome muito longo para valer a pena na maioria das vezes. Mas em funções puras é onde elas brilham. Se você não estiver familiarizado com sequências, elas são basicamente como splats em alguns outros idiomas; se você usar uma sequência em uma Listou na lista de argumentos de uma função, seus elementos serão automaticamente expandidos em slots separados. tão
{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]
Agora, em funções puras ##ou ##1é uma sequência de todos os argumentos. Da mesma forma, ##2é uma sequência de todos os argumentos a partir do segundo, ##3todos os argumentos a partir do terceiro etc. Portanto, para começar, podemos apenas reimplementar Sequencecomo ##&, economizando 5 bytes. Como exemplo de uso, isso nos fornece uma alternativa para Join@@list(consulte esta dica ), que não salva nenhum bytes, mas é bom saber de qualquer maneira:
##&@@@list
Isso aplaina efetivamente o primeiro nível de uma lista aninhada. O que mais podemos fazer com isso? Aqui está uma alternativa 2 bytes mais curta para RotateLeft:
RotateLeft@list
{##2,#}&@list
Só para essas coisas, vale a pena manter esse recurso em mente. No entanto, podemos fazer melhor! As sequências ficam realmente interessantes quando consideramos que os operadores são realmente implementados como funções ocultas. Por exemplo, a+bna verdade avalia como Plus[a,b]. Então, se dermos uma sequência ...
1+##&[1,2,3]
=> Plus[1,##]
=> Plus[1,1,2,3]
=> 7
Este truque foi usado nesta dica para economizar um byte Times, porque a justaposição tecnicamente também é apenas um operador:
1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6
Você também pode usá-lo para salvar um byte Unequalse você tiver um valor de caractere único ou variável que você sabe que não esteja em seus argumentos ( Nprovavelmente funcionará em 99% dos casos):
Unequal[a,b,c]
N!=##&[a,b,c]
Isso fica ainda mais interessante com operadores unários -e /- os dois últimos são realmente implementados em termos de multiplicação e exponenciação. Aqui está uma lista de coisas que você pode fazer, onde a última coluna assume que a função recebeu os argumentos a, b, c:
Operator Function Expanded Equivalent to
+## Plus[##] Plus[a,b,c] a+b+c
1## Times[1,##] Times[1,a,b,c] a*b*c
-## Times[-1,##] Times[-1,a,b,c] -a*b*c
x+## Plus[x,##] Plus[x,a,b,c] x+a+b+c
x-## Plus[x,Times[-1,##]] Plus[x,Times[-1,a,b,c]] x-a*b*c
x## Times[x,##] Times[x,a,b,c] x*a*b*c
x/## Times[x,Power[##,-1]] Times[x,Power[a,b,c,-1]] x*a^b^c^-1
##/x Times[##,Power[x,-1]] Times[a,b,c,Power[x,-1]] a*b*c/x
x^## Power[x,##] Power[x,a,b,c] x^a^b^c
##^x Power[##,x] Power[a,b,c,#] a^b^c^x
x.## Dot[x,##] Dot[x,a,b,c] x.a.b.c
Outros operadores comuns são !=, ==, &&, ||. Os menos comuns para se manter em mente são |, @*, /*. Para concluir, aqui está um pequeno truque de bônus:
#### Times[##,##] Times[a,b,c,a,b,c] (a*b*c)^2
Continue experimentando isso e deixe-me saber se você encontrar outras aplicações úteis ou particularmente interessantes!
Sqrt@2ou 2^.5=>√2
a[[1]]=>a〚1〛
#+#2&=>+##&
Flatten@a=> Join@@a(às vezes)
Function[x,x^2]=> xx^2ou#^2&
a〚1;;-1;;2〛=>a〚;;;;2〛
a〚2;;-1 ;;2〛=>a〚2;;;;2〛
a〚All,1〛=>a〚;;,1〛
{{1}}〚1,1〛=>Tr@{{1}}
0&~Array~10=>0Range@10
Range[10^3]=>Range@1*^3
〚e use 〛3 bytes cada (assuma UTF8) #
Inspirado pela recente descoberta de Dennis para Julia , pensei em investigar isso no Mathematica. Eu sabia que o Mathematica define um grande número de operadores não utilizados, mas nunca prestou muita atenção a ele.
Para referência, a lista de todos os operadores pode ser encontrada aqui na forma de uma tabela de precedência. O triângulo na última coluna indica se esse operador tem um significado interno ou não. Embora nem todos os que não podem ser definidos facilmente, a maioria deles pode.
Convenientemente, existem dois operadores não utilizados com um ponto de código menor que 256, para que possam ser usados como bytes únicos em um arquivo de origem codificado ISO 8859-1:
± (0xB1) pode ser usado como um operador de prefixo unário ou como um operador de infixo binário.· (0xB7) pode ser usado como um operador de infix variável ou n-ária, para n> 2.Porém, há mais um problema: por alguma razão estranha ao definir esses operadores, você precisa de um espaço na frente deles, ou o Mathematica tenta analisar uma multiplicação. Ao usá-los, você não precisa de espaços:
±x_:=2x
x_ ±y_:=x+y
x_ ·y_ ·z_:=x*y+z
Print[±5] (* 10 *)
Print[3±4] (* 7 *)
Print[3·4·5] (* 17 *)
Compare isso com:
f@x_:=2x
x_~g~y_:=x+y
h[x_,y_,z_]:=x*y+z
Print[f@5] (* 10 *)
Print[3~g~4] (* 7 *)
Print[h[x,y,z]] (* 17 *)
Portanto, isso economiza um byte ao definir a função e dois bytes ao usá-la. Observe que a definição de ·não salvará bytes para quatro operandos e começará a custar bytes para mais operandos, mas o uso ainda poderá salvar bytes, dependendo da precedência dos operadores usados nos argumentos. Também é bom observar que você pode definir de forma barata uma função variadica que pode ser chamada com muito mais eficiência:
x_ ·y__:={y}
Print[1·2·3·4·5] (* {2, 3, 4, 5} *)
Mas observe que não é possível chamar facilmente essas funções variadas com um único argumento. (Você pode fazer isso CenterDot[x]ou, ##&[]·xse realmente precisar, há uma boa chance de você estar melhor com uma solução diferente.)
Obviamente, isso não está salvando nada para soluções em que uma função sem nome é suficiente, mas às vezes você precisa definir funções auxiliares para uso posterior, e às vezes é mais curto definir funções nomeadas, por exemplo, para definir definições diferentes para parâmetros diferentes. Nesses casos, o uso de um operador pode salvar uma quantidade decente de bytes.
Observe que o uso desses arquivos codificados ISO 8859-1 precisa $CharacterEncodingser definido como um valor compatível, como o padrão do Windows WindowsANSI. Em alguns sistemas, esses padrões UTF-8não podem ler esses pontos de código a partir de bytes únicos.
A abordagem ingênua para escolher entre ye z, dependendo de xser 0ou 1não
If[x<1,y,z]
No entanto, há uma maneira mais curta:
y[z][[x]]
Isso funciona porque [[0]]dá a Headexpressão de, neste caso y, enquanto [[1]]apenas fornece o primeiro elemento - nesse caso, o primeiro argumento z,.
Você pode usar isso para escolher entre mais de dois valores:
u[v,w][[x]]
Observe que isso não funcionará se ufor uma função que realmente avalia algo. É importante que o Mathematica continue u[v,w]como está. No entanto, isso funciona na maioria dos casos, incluindo se ué um número, uma sequência ou uma lista.
Os créditos para esse truque vão para alefalpha - eu descobri isso em uma de suas respostas.
Se xfor baseado em 1 e não em zero, use apenas
{y,z}[[x]]
ou
{u,v,w}[[x]]
Em alguns casos raros, você pode até usar o fato de que a multiplicação não é avaliada para alguns valores:
{"abc","def"}[[x]]
("abc""def")[[x]]
Observe, porém, que o Mathematica realmente reordenará os argumentos, de uma multiplicação se permanecer sem avaliação, portanto, o acima é idêntico a
("def""abc")[[x]]
LengthIsso foi totalmente reescrito com algumas sugestões de LegionMammal978 e Misha Lavrov. Muito obrigado a ambos.
Em muitos casos, Lengthpode ser reduzido um pouco usando Tr. A idéia básica é transformar a entrada em uma lista de 1s, para que a Trsoma seja igual à duração da lista.
A maneira mais comum de fazer isso é usar 1^x(para uma lista x). Isso funciona porque Poweré Listablee 1^npara a maioria dos valores atômicos né justo 1(incluindo todos os números, cadeias e símbolos). Portanto, já podemos salvar um byte com isso:
Length@x
Tr[1^x]
Obviamente, isso pressupõe que xé uma expressão com maior precedência que ^.
Se xcontiver apenas 0s e 1s, podemos salvar outro byte usando Factorial(supondo xque a precedência seja maior que !):
Length@x
Tr[x!]
Em alguns casos raros, xpode ter precedência menor do ^que a multiplicação, mas ainda maior. Nesse caso, ele também terá menor precedência do que @, portanto, realmente precisamos comparar com Length[x]. Um exemplo desse operador é .. Nesses casos, você ainda pode salvar um byte com este formulário:
Length[x.y]
Tr[0x.y+1]
Finalmente, algumas observações sobre que tipo de lista isso funciona:
Como mencionado na parte superior, isso funciona em listas simples contendo apenas números, seqüências de caracteres e símbolos. No entanto, ele também funcionará em algumas listas mais profundas, embora na verdade calcule algo ligeiramente diferente. Para uma matriz retangular n- D, use Trfornece a menor dimensão (em oposição à primeira). Se você sabe que a dimensão mais externa é a mais curta, ou sabe que são todas iguais, as Trexpressões -existem ainda Length.
Length@x == Tr[1^x]. Deve funcionar com a maioria das listas.
Tr[x!]vez de Tr[1^x]salvar um byte no caso especial em que xapenas contém zeros e uns.
Explore soluções recursivas - o Mathematica é multiparadigma, mas a abordagem funcional é geralmente a mais econômica. NestWhilepode ser uma solução muito compacta para pesquisar problemas NestWhileListe FoldListé poderosa quando você precisa retornar ou processar os resultados de iterações intermediárias. Map (/@), Apply (@@, @@@), MapThread, E realmente tudo sobre o Wolfram Programação Funcional página de documentação é coisa potente.
Formulário reduzido para incremento / decremento - por exemplo, em vez de While[i<1,*code*;i++]você pode fazerWhile[i++<1,*code*]
Não esqueça que você pode pré-incrementar / diminuir - por exemplo, em --ivez de i--. Às vezes, isso pode economizar alguns bytes no código circundante, eliminando uma operação preparatória.
Corolário de # 5 de David Carraher: Quando a mesma função é usada várias vezes, atribuir um símbolo a ela pode salvar bytes. Por exemplo, se você estiver usando ToExpressionquatro vezes em uma solução, t=ToExpressionpoderá usá-lo t@*expression*posteriormente. No entanto, antes de fazer isso, considere se a aplicação repetida da mesma função indica uma oportunidade para uma abordagem recursiva mais econômica.
{}se você estiver usando @@@.Em alguns casos, você pode encontrar uma expressão como:
f@@@{{a,b},{c,d}}
É possível reduzir bytes escrevendo:
f@@@{a|b,c|d}
Alternativestem uma precedência muito baixa, por isso geralmente é bom escrever expressões (uma exceção notável são funções puras; você pode usá-lo apenas no elemento mais à esquerda de Alternatives).
f@@@{f@a|b~g~1,#^2&@c|d@2}
Observe que f@@a|b|c(em vez de f@@{a,b,c}) não funciona porque Applytem uma precedência maior que Alternative.
Nesse caso, você deve simplesmente usar f@@{a,b,c}.
Formulários do operador
O Mathematica 10 suporta as chamadas "formas de operador", o que basicamente significa que algumas funções podem ser curry. Currying uma função é criar uma nova função, corrigindo um de seus operadores. Digamos, você está usando SortBy[list, somereallylongfunction&]muitos lists diferentes . Antes, você provavelmente teria atribuído SortBya sea função pura para fassim
s=SortBy;
f=somereallylongfunction&;
list1~s~f;
list2~s~f;
list3~s~f;
Agora você pode curry SortBy, o que significa que agora você pode fazer
s=SortBy[somereallylongfunction&];
s@list1;
s@list2;
s@list3;
O mesmo funciona para um monte de outras funções, que levam um argumento lista ou função, incluindo (mas não limitado a) Select, Map, Nearest, etc.
ybeltukov no Mathematica.SE conseguiu produzir uma lista completa dos seguintes :
{"AllTrue", "AnyTrue", "Append", "Apply", "AssociationMap", "Cases",
"Count", "CountDistinctBy", "CountsBy", "Delete", "DeleteCases",
"DeleteDuplicatesBy", "Extract", "FirstCase", "FirstPosition",
"FreeQ", "GroupBy", "Insert", "KeyDrop", "KeyExistsQ", "KeyMap",
"KeySelect", "KeySortBy", "KeyTake", "Map", "MapAt", "MapIndexed",
"MatchQ", "MaximalBy", "MemberQ", "Merge", "MinimalBy", "NoneTrue",
"Position", "Prepend", "Replace", "ReplacePart", "Scan", "Select",
"SelectFirst", "SortBy", "StringCases"}
Composição e composição correta
Existem novas abreviações para Composition( @*) e RightComposition( /*). Um exemplo obviamente artificial, em que estes podem salvar caracteres, é visto nas três linhas equivalentes a seguir
Last@Range@# & /@ Range[5]
Last@*Range /@ Range[5]
Range /* Last /@ Range[5]
Não há necessidade de código como este:
f[]:=DoSomething[1,2]
(*...*)
f[]
(*...*)
f[]
Você pode simplesmente usar uma variável com :=para forçar a reavaliação do lado direito:
f:=DoSomething[1,2]
(*...*)
f
(*...*)
f
Isso também significa que você pode alternar qualquer ação que você executa com freqüência (mesmo que seja apenas algo parecido n++) para um único caractere ao custo de 5 bytes. Então, no caso de n++ele pagar depois do quarto uso:
n++;n++;n++;n++
f:=n++;f;f;f;f
%para obter uma variável livreEssa dica é aplicável apenas se o ambiente REPL do Mathematica puder ser assumido. %não está definido quando o código é executado como um script.
Quando você puder usar os recursos do REPL, não faça isso:
a=someLongExpression;some[other*a,expression@a,using^a]
Em vez disso, lembre-se de que o Mathematica armazena a última expressão avaliada (terminada por nova linha) em %:
someLongExpression;
some[other*%,expression@%,using^%]
A nova linha adicionada custa um byte, mas você está economizando dois com a remoção a=. Portanto, no geral, isso economiza um byte.
Em alguns casos (por exemplo, quando você deseja imprimir o valor de aqualquer maneira), pode até deixar de fora ;, salvando dois bytes:
someLongExpression
some[other*%,expression@%,using^%]
Um ou dois bytes podem parecer razoavelmente menores, mas esse é um caso importante, pois torna a extração de expressões repetidas (que é uma técnica muito comum) muito mais útil ao jogar golfe:
A técnica normal de extrair expressões repetidas custa quatro bytes de sobrecarga, que precisam ser salvos por outros usos da expressão. Aqui está uma tabela curta do número mínimo de usos de uma expressão (pelo comprimento da expressão) para extração em uma variável nomeada para salvar qualquer coisa:
Length Min. Uses
2 6
3 4
4 3
5 3
6 2
... 2
Usando a variável sem nome, será possível salvar alguns bytes com muito mais frequência:
When ; is required When ; can be omitted
Length Min. Uses Length Min. Uses
2 5 2 4
3 3 3 3
4 3 4 2
5 2 ... 2
... 2
Eu não penso %%ou %nposso ser usado para jogar golfe, porque se você não os usar pelo menos duas vezes, poderá colocar a expressão exatamente onde é necessário. E se você usá-lo duas vezes, o caractere adicional no nome da variável cancela a economia por omitir alguns x=.
Este é essencialmente um corolário dessa dica, mas é uma tarefa suficientemente comum que acho que merece sua própria resposta.
A maneira ingênua de verificar se uma lista está em ordem é usar
OrderedQ@a
Podemos fazer um byte melhor com
Sort@a==a
No entanto, isso não funcionará se ainda não tivermos o que queremos verificar em uma variável. (Precisávamos de algo como o Sort[a=...]==aque é desnecessariamente longo.) No entanto, há outra opção:
#<=##&@@a
A melhor coisa é que isso pode ser usado para verificar se a entrada é classificada inversamente para a mesma contagem de bytes:
#>=##&@@a
Mais um byte pode ser salvo se: a) sabemos que os elementos da lista são distintos eb) sabemos um limite inferior entre 0 e 9 (inclusive; ou limite superior para ordem inversa):
0<##&@@a
5>##&@@a
Para ver por que isso funciona, consulte "Sequências de argumentos" na dica vinculada na parte superior.
##>0&@@a. Semelhante para o limite superior para classificado.
Em vez de StringRepeat[str,n]usar (0Range[n]+str)<>"". Ou se strnão depender de nenhum argumento de slot, o melhor é Array[str&,n]<>""usar esta dica.
StringRepeat[s,n+1]usar Array[s&,n]<>s(mesmo quando você já possui n+1uma variável).
Table[str,n]<>""
Se você precisar de uma lista de números ordenados ao contrário, não use
Reverse@Sort@x
mas
-Sort@-x
para salvar seis bytes. A classificação por um valor negativo também é útil para SortBycenários:
Reverse@SortBy[x,Last]
SortBy[x,-Last@#&]
-Sort@-x?
Você pode colar uma expressão na Breakqual pode salvar um ou dois caracteres. Exemplo ( outros detalhes não são utilizados para maior clareza ):
result = False;
Break[]
pode ser transformado em
Break[result = False]
para salvar um caractere. Se a expressão em questão não tiver precedência menor que o aplicativo de funções, você poderá salvar outro caractere:
Print@x;
Break[]
pode ser transformado em
Break@Print@x
Embora não documentado, o argumento Breakparece retornar ao loop circundante, o que pode potencialmente levar a ainda mais economia.
Para remover todo o espaço em branco de uma string s, use
StringSplit@s<>""
Ou seja, use StringSplito padrão (dividido em componentes que não sejam espaços em branco) e simplesmente junte-os novamente. O mesmo provavelmente ainda é o mais curto se você quiser se livrar de qualquer outro caractere ou substring:
s~StringSplit~"x"<>""
RangeUma tarefa muito comum é aplicar algum tipo de função a todos os números de 1 a a n(geralmente dados como entrada). Existem essencialmente três maneiras de fazer isso (usando uma função de identidade sem nome como exemplo):
#&/@Range@n
Array[#&,n]
Table[i,{i,n}]
Costumo optar pelo primeiro (por qualquer motivo), mas essa raramente é a melhor escolha.
Arrayvez dissoO exemplo acima mostra que o uso Arraytem a mesma contagem de bytes. No entanto, tem a vantagem de ser uma expressão única. Em particular, se você quiser processar o resultado com uma função, fpoderá usar a notação de prefixo, que salva um byte Range:
f[#&/@Range@n]
f@Array[#&,n]
Além disso, você pode omitir parênteses em torno de sua função sem nome, com a qual você pode precisar Range, por exemplo
15/(#&)/@Range@n
15/Array[#&,n]
Se você não quiser usá-lo mais (ou com um operador que tenha menor precedência), poderá escrever- Arrayse em notação de infixo e também salvar um byte:
#&/@Range@n
#&~Array~n
Portanto, Arrayé quase certamente melhor que Range.
Tablevez dissoAgora, a tabela precisa compensar 3 bytes ou pelo menos 2 quando a notação infix é uma opção:
#&/@Range@n
i~Table~{i,n}
Quando nãoTable estiver usando notação infix, poderá omitir parênteses se sua função consistir em várias instruções:
(#;#)&/@Range@n
Table[i;i,{i,n}]
Isso ainda é mais longo, mas gera economia extra no caso mencionado abaixo.
A economia real deriva do fato de Tabledar um nome à variável em execução não deve ser descartada. Freqüentemente, você terá funções anônimas aninhadas nas quais deseja usar a variável externa dentro de uma das funções internas. Quando isso acontece, Tableé mais curto que Range:
(i=#;i&[])&/@Range@n
Table[i&[],{i,n}]
i&[]~Table~{i,n}
Você não apenas salva os caracteres para atribuir i, como também pode reduzir a função a uma única instrução no processo, o que permite o uso de notação infix sobre ela. Para referência, Arraytambém é mais longo neste caso, mas ainda menor que Range:
(i=#;i&[])&~Array~n
Range?Sempre que você não precisar de uma chamada de função para processar os valores, por exemplo, quando o mapeamento puder ser realizado por meio de uma operação vetorizada. Por exemplo:
5#&~Array~n
5Range@n
#^2&~Array~n
Range@n^2
Obviamente, também é mais curto se você não deseja mapear nenhuma função, por exemplo,
Mean@Array[#&,n]
Mean@Range@n
f/@Range[x]regularmente ... #
Algumas construções i=1;While[cond[i],i++]são boas como estão, mas há uma alternativa que é dois bytes mais curta:
1//.i_/;cond[i]:>i+1
O código acima substitui repetidamente um número ipor i+1enquanto ele atende à condição cond[i]. Nesse caso, icomeça em 1.
Observe que o número máximo padrão de iterações é 2 ^ 16 (= 65536). Se você precisar de mais iterações do que isso, Whileseria melhor. ( MaxIterations->∞é muito longo)
Às vezes, você pode substituir Ifpor um operador lógico.
Por exemplo, digamos que você queira criar uma função que verifique se um número é primo e print 2*(number) - 1é se for verdadeiro:
If[PrimeQ@#,Print[2#-1]]&
É mais curto se você usar &&:
PrimeQ@#&&Print[2#-1]&
Mesmo quando você tem várias expressões, ainda salva byte (s):
If[PrimeQ@#,a++;Print[2#-1]]&
PrimeQ@#&&a++&&Print[2#-1]&
(* or *)
PrimeQ@#&&(a++;Print[2#-1])&
Você pode usar ||para casos em que deseja que a condição seja False:
If[!PrimeQ@#,Print[2#-1]]&
(* or *)
If[PrimeQ@#,,Print[2#-1]]&
(* can become *)
PrimeQ@#||Print[2#-1]&
Esses truques funcionam porque os operadores lógicos podem sofrer um curto-circuito ; o segundo argumento e, posteriormente, nem precisam ser expressões booleanas válidas.
Obviamente, isso não funcionará se você precisar do valor de retorno Ifou quando precisar de argumentos verdadeiros e falsos de If.
Aqui está uma lista com vários formulários de entrada do operador que podem reduzir muitas coisas. Algumas delas foram mencionadas em outros posts, mas a lista é longa e sempre me surpreendo ao descobrir algumas coisas novas por lá:
Optional (:)Optional (:) pode ser usado para expandir listas em substituições, sem precisar definir uma regra separada para a expansão.
Esta resposta por mim e esta resposta por @ngenisis são exemplos.
Uso
... /. {p___, a_: 0, b_, q___} /; cond[b] :> ...
A substituição acima usa primeiro o padrão {p___, a_, b_, q___}e encontra uma correspondência que batenda a uma determinada condição.
Quando nenhuma correspondência é encontrada, ela é omitida a_e, em vez disso , é procurada {p___, b_, q___}. anão está incluído na pesquisa e Assume-se que o valor 0.
Observe que a segunda pesquisa de padrões funcionaria apenas para bisso ocorrendo no início da lista; se um bvalor que satisfaz uma condição estiver no meio, então {p___, a_, b_, q___}(que tem uma precedência mais alta) corresponderá a ele.
A substituição é equivalente a anexar a 0quando bocorre uma condição satisfatória no início da lista. (ou seja, não há necessidade de definir uma regra separada {b_, q___} /; cond[b] :> ...)
Para código de golfe, Functionargumentos puros são mais comumente referenciados usando Slots; por exemplo, #para o primeiro argumento, #2para o segundo, etc. (veja esta resposta para mais detalhes).
Em muitos casos, você desejará aninhar Functions. Por exemplo, 1##&@@#&é um Functionque pega uma lista como seu primeiro argumento e gera o produto de seus elementos. Aqui está essa função em TreeForm:
Argumentos passados para o nível superior Functionsó pode preenchimento Slots e SlotSequences presente no nível superior, que neste meio de caso que o SlotSequenceno interior Functionnão terá qualquer maneira de acessar argumentos para o nível superior Function.
Em alguns casos, no entanto, convém que um Functionaninhado em outro Functionseja capaz de referenciar argumentos para o externo Function. Por exemplo, você pode querer algo como Array[fun,...]&, onde a função fundepende de um argumento para o nível superior Function. Para concretude, digamos que fundeve dar ao restante do quadrado do seu módulo de entrada a entrada para o nível superior Function. Uma maneira de conseguir isso é atribuir o argumento de nível superior a uma variável:
(x=#;Array[Mod[#^2,x]&,...])&
Onde quer que xapareça no interior Function Mod[#^2,x]&, ele se referirá ao primeiro argumento para o exterior Function, enquanto que #se referirá ao primeiro argumento ao interior Function. Uma abordagem melhor é usar o fato de Functionter uma forma de dois argumentos em que o primeiro argumento é um símbolo ou lista de símbolos que representará argumentos nomeados para Function(em oposição a Slots sem nome ). Isso acaba poupando três bytes neste caso:
xArray[Mod[#^2,x]&,...]
é o caractere de uso privado de três bytes que U+F4A1representa o operador de infixo binário \[Function]. Você também pode usar a forma binária de Functiondentro de outra Function:
Array[xMod[x^2,#],...]&
Isso é equivalente ao acima. A razão é que, se você estiver usando argumentos nomeados, então SlotS e SlotSequencessão assumidos pertencer a próxima Functionacima do qual não utiliza argumentos nomeados.
Agora, apenas porque podemos aninhar Functions dessa maneira, não significa que devemos sempre. Por exemplo, se quisermos escolher os elementos de uma lista que são menores que a entrada, podemos ficar tentados a fazer algo como o seguinte:
Select[...,xx<#]&
Na verdade, seria mais curto usar Casese evitar a necessidade de um aninhado Functioninteiramente:
Cases[...,x_/;x<#]&
Você pode salvar um byte por trabalhar em torno Prependou PrependTo:
l~Prepend~x
{x}~Join~l
{x,##}&@@l
ou
l~PrependTo~x
l={x}~Join~l
l={x,##}&@@l
Infelizmente, isso não ajuda no mais comum Append, o que parece ser o equivalente mais curto de um Array.push()em outros idiomas.
BlockMapé Partition+MapEssa dica também pode ser intitulada "Leia as notas de versão, todas elas". (Para referência, aqui estão as notas de versão 10.2 e aqui da versão 10.3 de hoje .)
De qualquer forma, mesmo versões menores contêm diversos recursos novos, e um dos mais úteis (para jogar golfe) da versão 10.2 é a nova BlockMapfunção. Essencialmente combina Partitione Map, o que é ótimo para os golfistas, porque Partitioné usado com bastante frequência e é um nome de função realmente irritantemente longo. A nova função não será reduzida Partitionpor si só, mas sempre que você quiser mapear uma função para as partições (o que provavelmente acontece com mais frequência), agora você pode salvar um ou dois bytes:
#&/@l~Partition~2
BlockMap[#&,l,2]
#&/@Partition[l,3,1]
BlockMap[#&,l,3,1]
A economia fica ainda maior quando a nova posição da função sem nome permite salvar alguns parênteses:
#&@@(#&/@Partition[l,3,1])
#&@@BlockMap[#&,l,3,1]
Infelizmente, não faço ideia por que não adicionei também BlockApplyenquanto estavam lá ...
Observe também que BlockMapnão suporta o quarto parâmetro com o qual você pode usar Partitionpara obter uma lista cíclica:
Partition[Range@5, 2, 1, 1]
(* Gives {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 1}} *)
BlockMap[f, Range@5, 2, 1, 1]
(* Nope... *)
Se sua resposta acabar usando as mesmas funções ou expressões várias vezes, considere armazená-las em variáveis.
Se sua expressão é longa le você a usa nvezes, normalmente usaria l * nbytes.
No entanto, se você armazená-lo em uma variável de comprimento 1, levaria apenas 3 + l + nbytes (ou 2 + l + nbytes, se você atribuir a variável aonde não precisará CompoundExpression (;)nem parênteses).
Por exemplo, vamos considerar um problema simples, encontrando primos gêmeos menores que N.
Pode-se escrever esta solução de 54 bytes:
Select[Range@#,PrimeQ@#&&(PrimeQ[#+2]||PrimeQ[#-2])&]&
Neste exemplo, a função PrimeQé usada três vezes.
Ao atribuir PrimeQum nome de variável, a contagem de bytes pode ser reduzida. Ambos são 48 bytes (54 - 6 bytes):
Select[p=PrimeQ;Range@#,p@#&&(p[#+2]||p[#-2])&]&
Select[Range@#,(p=PrimeQ)@#&&(p[#+2]||p[#-2])&]&
Sortvez deSortByPara listas como list = {{1, "world"}, {0, "universe"}, {2, "country"}}, as três instruções a seguir são quase equivalentes.
SortBy[list,#[[1]]&]
list~SortBy~First
Sort@list
SelecteSortByÀs vezes, precisamos escolher entradas de um conjunto maior e classificá-las para encontrar um mínimo / máximo. Sob algumas circunstâncias , duas operações podem ser combinadas em uma.
Por exemplo, no mínimo, as duas instruções a seguir são quase equivalentes.
SortBy[Select[l,SomeFormula==SomeConstant&],SortValue&]
SortBy[l,SortValue+99!(SomeFormula-SomeConstant)^2&]
e
SortBy[Select[l,SomeFormula!=SomeConstant&],SortValue&]
SortBy[l,SortValue+1/(SomeFormula-SomeConstant)&]
1/0é ComplexInfinity, que é "maior" que todos os números reais.
Para uma lista de valores-chave, por exemplo:
{SortValue,#}&/@SortBy[Select[l,SomeFormula==SomeConstant],SortValue&]
Sort[{SortValue+99!(SomeFormula-SomeConstant)^2,#})&/@l]
Arraycom##&Ao usar uma Matriz multidimensional para calcular uma lista de resultados que precisam ser nivelados, use ##&como o quarto argumento. Isso substitui as cabeças da matriz por ##&(equivalente a Sequence) em vez de List, portanto, o resultado final será um (plano) Sequencede resultados.
Em duas dimensões, compare
{Array[f,dims,origin,##&]}
Join@@Array[f,dims,origin]
Obviamente,
Join@@Array[f,dims]
ainda são 2 (ou 3, se a notação infix puder ser usada) bytes menores que
{Array[f,dims,1,##&]}.
Em três ou mais dimensões, {Array[f,dims,origin,##&]}é sempre menor que a alternativa, mesmo que a origem seja 1.
{Array[f,dims,1,##&]}
f~Array~dims~Flatten~2
Os valores padrão lidam com argumentos de padrão ausentes de maneira eficiente. Por exemplo, se quisermos correspondência de padrões Exp[c_*x]em uma regra para qualquer valor de c, a ingênua
Exp[x] + Exp[2x] /. {Exp[c_*x] -> f[c], Exp[x] -> f[1]}
(* f[1] + f[2] *)
usa muito mais bytes do que se usarmos o valor padrão csempre que estiver ausente:
Exp[x] + Exp[2 x] /. Exp[c_.*x] -> f[c]
(* f[1] + f[2] *)
O uso de um padrão é indicado com um ponto após o padrão: c_..
Os valores padrão estão associados às operações: no exemplo acima, a operação está Timesinserida c_.*xe, c_portanto , um valor ausente é obtido do valor padrão associado a Times, que é 1. Para Plus, o valor padrão é 0:
Exp[x] + Exp[x + 2] /. Exp[x + c_.] -> f[c]
(* f[0] + f[2] *)
Para Powerexpoentes, o padrão é 1:
x + x^2 /. x^n_. -> p[n]
(* p[1] + p[2] *)
(Norm[#-#2]&)do que paraEuclideanDistance.