¿Qué consejos generales tienes para jugar al golf en Mathematica? Estoy buscando ideas que puedan aplicarse a los problemas de código de golf en general que sean al menos algo específicos de Mathematica (por ejemplo, "eliminar comentarios" no es una respuesta).
(Norm[#-#2]&)
en lugar deEuclideanDistance
.Algunas funciones integradas con nombres largos se pueden reemplazar con expresiones más cortas.
Por ejemplo:
Total
=>Tr
Transpose
=>Thread
o\[Transpose]
True
=>1<2
False
=>1>2
Times
=>1##&
Alternatives
=>$|##&
IntegerQ
=>⌊#⌋==#&
a[[1]]
=>#&@@a
a[[All,1]]
=>#&@@@a
ConstantArray[a,n]
=>Array[a&,n]
oTable[a,{n}]
Union@a
=>{}⋃a
oa⋃a
ToExpression@n
=>FromDigits@n
sin
es un númeroDivisible[n,m]
=>m∣n
FromDigits[n,2]
=>Fold[#+##&,n]
Sin
es una lista de0
s y1
sComplex@z
=>{1,I}.z
dondez
hay una lista del formulario{x,y}
fuente
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}}]
Fold
trucoFromDigits
también funciona para cualquier otra base, excepto10
. Por ejemploFromDigits[n,5]
->Fold[4#+##&,n]
(con la ventaja de guardar un byte extra para bases100
y1000
).U+F3C7
.Echo
sea una opción, porque imprime>>
(y un espacio) en STDOUT antes de imprimir la cadena real.Complex[x,y] => {1,I}.{x,y}
, creo quex+y*I
es mucho más corto con el mismo efecto?Listas con valores repetidos
Este es un vector bastante común para trabajar con:
Resulta que esto puede ser acortado por un byte:
Incluso se guardan más bytes si el vector es más largo que dos ceros. Esto también se puede utilizar para inicializar matrices cero, por ejemplo, lo siguiente proporciona una matriz de ceros 2x2:
Esto también se puede utilizar para valores distintos de cero si son lo suficientemente grandes, suficientes o negativos. Compare los siguientes pares:
Pero recuerde que a partir de 6 valores, es mejor
1~Table~6
en este caso (potencialmente más temprano, dependiendo de los requisitos de precedencia).La razón por la que esto funciona es que
,
introduce dos argumentos en la lista, pero los argumentos omitidos (en cualquier lugar de Mathematica) sonNull
s implícitos . Además, la multiplicación esListable
y0*x
es0
para casi cualquierx
(excepto para cosas comoInfinity
yIndeterminate
), así que aquí está lo que está sucediendo:Para las listas de
1
s, puede usar un truco similar haciendo uso de las reglas de exponenciación. Hay dos formas diferentes de guardar bytes si tiene al menos tres1
s en la lista:fuente
1^{,,,}
es un byte más pequeño que0{,,,}+1
.{,,}^0
. Editaré la publicación.Conoce tus argumentos de función pura
Al jugar al golf, a menudo empleará un enfoque funcional, en el que utiliza funciones anónimas (puras) con la
&
sintaxis abreviada. Hay muchas maneras diferentes de acceder a los argumentos de una función de este tipo, y a menudo puede reducir un par de bytes al tener un buen conocimiento de las posibilidades.Acceso a argumentos únicos
Probablemente lo sepas si has usado funciones puras antes. El n º argumento se denomina
#n
, y#
actúa como un alias para#1
. Entonces, si, por ejemplo, desea escribir una función que tome como parámetros otra función y su argumento (para pasar el argumento a esa función), useEsto no funciona con números negativos (como los que podría usar al acceder a las listas).
Acceso a argumentos con nombre (nuevo en V10)
Una de las principales características nuevas del lenguaje en Mathematica 10 es
Association
s, que son básicamente mapas de valores clave con tipos de clave arbitrarios, escritos comoSi dicha asociación se pasa como primer argumento a una función pura, puede acceder a algunos de sus argumentos como parámetros con nombre:
Tenga en cuenta que
#
todavía se refiere a toda la asociación como se esperaba. Para que los parámetros nombrados funcionen, las claves deben ser cadenas (no funcionará si utiliza variables indefinidas, por ejemplo), y esas cadenas deben comenzar con una letra y solo contener letras y dígitos.El argumento del "yo"
#0
Una característica menos conocida es que
#0
también existe y le proporciona el objeto de función en sí. Esto puede ser realmente útil en quines y quines generalizados. De hecho, la quine más corta de Mathematica (que conozco) esLo que es un poco molesto es que no te dará los caracteres exactos que ingresaste. Por ejemplo, si se usa
@
para la aplicación de funciones, todavía se representará como[...]
y se insertarán espacios en algunos lugares. Esto generalmente hará que la quine sea un poco más larga de lo que le gustaría, pero siempre funcionará, primero jugando al quine y luego simplemente copiando su salida, que ahora debería ser una quine real.Además de quines, esto también significa que puede escribir código recursivo sin tener que nombrar su función. Compare estas tres implementaciones de Fibonacci (ingenuas pero golfistas):
Secuencias de argumentos
Ahora aquí es donde comienza la verdadera magia. Las secuencias no se usan a menudo en el golf, porque
Sequence
es un nombre demasiado largo para que valga la pena la mayor parte del tiempo. Pero en las funciones puras es donde brillan. Si no está familiarizado con las secuencias, básicamente son como símbolos en algunos otros idiomas, si usa una secuencia en unaList
lista de argumentos de una función, sus elementos se expandirán automáticamente en ranuras separadas. Asi queAhora, en funciones puras
##
o##1
es una secuencia de todos los argumentos. Del mismo modo,##2
es una secuencia de todos los argumentos que comienzan desde el segundo,##3
todos los argumentos que comienzan desde el tercero, etc. Entonces, para empezar, podemos volver a implementarSequence
como##&
, ahorrando 5 bytes. Como ejemplo de uso, esto nos proporciona una alternativa aJoin@@list
(vea este consejo ), que no guarda ningún byte, pero es bueno saber de todos modos:Esto efectivamente aplana el primer nivel de una lista anidada. ¿Qué más podemos hacer con esto? Aquí hay una alternativa más corta de 2 bytes para
RotateLeft
:Solo por estas cosas vale la pena tener en cuenta esta característica. Sin embargo, podemos hacerlo mejor! Las secuencias se vuelven realmente interesantes cuando se considera que los operadores se implementan realmente como funciones ocultas. Por ejemplo, en
a+b
realidad evalúa aPlus[a,b]
. Entonces, si le damos una secuencia ...Este truco se ha utilizado en este consejo para guardar un byte
Times
, porque técnicamente la yuxtaposición también es solo un operador:También puede usarlo para guardar un byte
Unequal
si tiene un valor o variable de un solo carácter que sabe que no está en sus argumentos (N
probablemente funcionará en el 99% de los casos):Esto se vuelve aún más interesante con los operadores unarios y
-
y/
- los dos últimos se llevan a la práctica los términos de la multiplicación y exponenciación. Aquí hay una lista de cosas que puede hacer, donde la última columna asume que la función pasó los argumentosa, b, c
:Otros operadores son comunes
!=
,==
,&&
,||
. Menos comunes a tener en cuenta son|
,@*
,/*
. Para concluir, aquí hay un pequeño truco extra:¡Siga experimentando con estos y avíseme si encuentra otras aplicaciones útiles o particularmente interesantes!
fuente
Sqrt@2
o2^.5
=>√2
a[[1]]
=>a〚1〛
#+#2&
=>+##&
Flatten@a
=>Join@@a
(a veces)Function[x,x^2]
=>xx^2
o#^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
fuente
〚
y〛
toma 3 bytes cada uno (suponga UTF8)Operadores como funciones
Inspirado por el reciente descubrimiento de Dennis para Julia , pensé en investigar esto para Mathematica. Sabía que Mathematica define una gran cantidad de operadores no utilizados, pero nunca le prestó mucha atención.
Como referencia, la lista de todos los operadores se puede encontrar aquí en forma de una tabla de precedencia. El triángulo en la última columna indica si ese operador tiene un significado incorporado o no. Si bien no todos los que no se pueden definir fácilmente, la mayoría sí.
Convenientemente, hay dos operadores no utilizados con un punto de código inferior a 256, de modo que se pueden usar como bytes individuales en un archivo fuente codificado ISO 8859-1:
±
(0xB1) se puede usar como operador de prefijo unario o como operador de infijo binario.·
(0xB7) se puede utilizar como operador infijo variadic o n-ary, para n> 2.Sin embargo, hay una trampa más: por alguna extraña razón al definir estos operadores, necesita un espacio delante de ellos, o Mathematica intenta analizar una multiplicación. Sin embargo, al usarlos no necesita espacios:
Compare esto con:
Esto ahorra un byte cuando se define la función y dos bytes cuando se usa. Tenga en cuenta que la definición de
·
no guardará bytes para cuatro operandos y comenzará a costar bytes para más operandos, pero el uso aún puede guardar bytes, dependiendo de la precedencia de los operadores utilizados en los argumentos. También es bueno tener en cuenta que puede definir de manera económica una función variada que luego se puede llamar de manera mucho más eficiente:Pero tenga en cuenta que no es fácilmente posible llamar a estas funciones variadas con un solo argumento. (Podría hacerlo
CenterDot[x]
o##&[]·x
si realmente lo necesita, hay una buena posibilidad de que esté mejor con una solución diferente).Por supuesto, esto no está guardando nada para soluciones en las que una función sin nombre es suficiente, pero a veces es necesario definir funciones auxiliares para su uso posterior, y a veces es más corto definir funciones con nombre, por ejemplo, para establecer diferentes definiciones para diferentes parámetros. En esos casos, usar un operador en su lugar puede ahorrar una cantidad decente de bytes.
Tenga en cuenta que el uso de estos archivos codificados ISO 8859-1
$CharacterEncoding
debe establecerse en un valor compatible, como el predeterminado de WindowsWindowsANSI
. En algunos sistemas, este valor predeterminadoUTF-8
no podrá leer estos puntos de código desde bytes individuales.fuente
Elegir valores basados en enteros
El enfoque ingenuo para elegir entre
y
yz
, dependiendo de six
es0
o1
esSin embargo, hay una forma más corta:
Esto funciona porque
[[0]]
da laHead
de una expresión, en este casoy
, mientras que[[1]]
solo da el primer elemento - en este caso el primer argumento,z
.Incluso puede usar esto para elegir entre más de dos valores:
Tenga en cuenta que esto no funcionará si
u
es una función que realmente se evalúa como algo. Es importante que Mathematica se mantengau[v,w]
como está. Sin embargo, esto funciona en la mayoría de los casos, incluso siu
es un número, una cadena o una lista.Los créditos para este truco van a alephalpha: descubrí esto en una de sus respuestas.
Si
x
se basa en 1 en lugar de en cero, solo useo
En algunos casos raros, incluso puede hacer uso del hecho de que la multiplicación no se evalúa para algunos valores:
Sin embargo, tenga en cuenta que Mathematica reordenará los argumentos, de una multiplicación si permanece sin evaluar, por lo que lo anterior es idéntico a
fuente
Alternativas a
Length
Esto ha sido completamente reescrito con algunas sugerencias de LegionMammal978 y Misha Lavrov. Muchas gracias a los dos.
En muchos casos,
Length
se puede acortar un poco haciendo uso deTr
. La idea básica es convertir la entrada en una lista de1
s, de modo que lasTr
sume , lo que equivale a la longitud de la lista.La forma más común de hacer esto es usar
1^x
(para una listax
). Esto funciona porquePower
esListable
y1^n
para la mayoría de los valores atómicosn
es justo1
(incluidos todos los números, cadenas y símbolos). Entonces ya podemos guardar un byte con esto:Por supuesto, esto supone que
x
es una expresión con mayor precedencia que^
.Si
x
contiene solo0
sy1
s, podemos guardar otro byte usandoFactorial
(suponiendo quex
tenga mayor prioridad que!
):En algunos casos raros,
x
podría tener una precedencia más baja que^
una precedencia aún mayor que la multiplicación. En ese caso, también tendrá una precedencia menor que@
, por lo que realmente necesitamos compararLength[x]
. Un ejemplo de tal operador es.
. En esos casos, aún puede guardar un byte con este formulario:Finalmente, algunos comentarios sobre qué tipo de listas funcionan:
Como se mencionó en la parte superior, esto funciona en listas planas que contienen solo números, cadenas y símbolos. Sin embargo, también funcionará en algunas listas más profundas, aunque en realidad calcula algo ligeramente diferente. Para una matriz rectangular n -D, el uso
Tr
le brinda la dimensión más corta (en oposición a la primera). Si sabe que la dimensión más externa es la más corta, o sabe que son todas iguales, entonces lasTr
expresiones -son equivalentes aLength
.fuente
Length@x == Tr[1^x]
. Debería funcionar con la mayoría de las listas.Tr[x!]
lugar deTr[1^x]
guardar un byte en el caso especial dondex
solo contiene ceros y unos.Explore soluciones recursivas : Mathematica es multi-paradigma, pero el enfoque funcional es a menudo el más económico.
NestWhile
puede ser una solución muy compacta a problemas de búsqueda, yNestWhileList
yFoldList
son poderosos cuando se necesita devolver o procesar los resultados de iteraciones intermedios.Map (/@)
,Apply (@@, @@@)
,MapThread
, Y realmente todo el contenido de Wolfram programación funcional página de documentación es potente cosas.Forma acortada para incremento / decremento : por ejemplo, en lugar de
While[i<1,*code*;i++]
que pueda hacerWhile[i++<1,*code*]
No olvide que puede aumentar / disminuir previamente : por ejemplo, en
--i
lugar dei--
. Esto a veces puede ahorrarle unos pocos bytes en el código circundante al eliminar una operación preparatoria.Corolario del n. ° 5 de David Carraher: cuando se usa la misma función muchas veces, asignarle un símbolo puede ahorrar bytes. Por ejemplo, si está usando
ToExpression
4 veces en una solución, let=ToExpression
permite usart@*expression*
después. Sin embargo, antes de hacer esto, considere si la aplicación repetida de la misma función indica una oportunidad para un enfoque recursivo más económico.fuente
MapThread
a menudo puede ser reemplazado por\[Transpose]
. TIO .No lo use
{}
si lo está usando@@@
.En algunos casos, puede encontrar una expresión como:
Es posible reducir bytes escribiendo:
Alternatives
tiene una precedencia muy baja, por lo que generalmente está bien escribir expresiones (una excepción notable son las funciones puras; solo puede usarlo en el elemento más a la izquierda deAlternatives
).Tenga en cuenta que
f@@a|b|c
(en lugar def@@{a,b,c}
) no funciona porqueApply
tiene una precedencia mayor queAlternative
.En este caso, simplemente debes usar
f@@{a,b,c}
.fuente
Solo Mathematica 10
Formularios de operador
Mathematica 10 admite las llamadas "formas de operador", lo que básicamente significa que algunas funciones se pueden cursar. Hacer curry de una función es crear una nueva función arreglando uno de sus operadores. Digamos que estás usando
SortBy[list, somereallylongfunction&]
muchoslist
s diferentes . Antes, es probable que haya asignadoSortBy
as
y la función pura af
por loAhora puedes curry
SortBy
, lo que significa que ahora puedes hacerLo mismo funciona para muchas otras funciones, que tienen una lista o función argumento, incluyendo (pero no limitado a)
Select
,Map
,Nearest
, etc.ybeltukov en Mathematica.SE pudo producir una lista completa de estos :
Composición y composición derecha
Hay nuevas shorthands para
Composition
(@*
) yRightComposition
(/*
). Un ejemplo obviamente ideado donde estos pueden guardar caracteres se ve en las siguientes tres líneas equivalentesfuente
No escriba funciones de argumento 0
No hay necesidad de código como este:
Simplemente puede usar una variable con
:=
para forzar la reevaluación del lado derecho:Esto también significa que puede alias cualquier acción que realice a menudo (incluso si es algo así
n++
) a un solo carácter a un costo de 5 bytes. Entonces, en el caso den++
que pague después del cuarto uso:fuente
Use
%
para obtener una variable libreEste consejo solo es aplicable si se puede suponer el entorno REPL de Mathematica.
%
no se define cuando el código se ejecuta como un script.Cuando pueda hacer uso de las funciones REPL, no haga esto:
En cambio, recuerde que Mathematica almacena la última expresión evaluada (terminada en nueva línea) en
%
:La nueva línea agregada cuesta un byte, pero está ahorrando dos al eliminar
a=
, por lo que, en general, esto ahorra un byte.En algunos casos (por ejemplo, cuando desea imprimir el valor de
a
todos modos), incluso puede dejar de lado;
, guardando dos bytes:Uno o dos bytes pueden parecer bastante menores, pero este es un caso importante, ya que hace que la extracción de expresiones repetidas (que es una técnica muy común) sea mucho más útil cuando se juega al golf:
La técnica normal de extraer expresiones repetidas cuesta cuatro bytes de sobrecarga, que deben guardarse mediante usos adicionales de la expresión. Aquí hay una breve tabla del número mínimo de usos de una expresión (por longitud de la expresión) para extracción en una variable con nombre para guardar cualquier cosa:
Al usar la variable sin nombre, será posible guardar un par de bytes con mucha más frecuencia:
No creo
%%
o%n
puedo usarlo para jugar al golf, porque si no los usas al menos dos veces, puedes poner la expresión justo donde se necesita. Y si lo usa dos veces, el carácter adicional en el nombre de la variable cancela los ahorros por omitir algunosx=
.fuente
Comprobando si una lista está ordenada
Esto es esencialmente un corolario de este consejo, pero esta es una tarea suficientemente común que creo que justifica su propia respuesta.
La forma ingenua de verificar si una lista está en orden es usar
Podemos hacer un byte mejor con
Sin embargo, esto no funciona si ya no tenemos lo que queremos registrar en una variable. (Necesitaríamos algo como lo
Sort[a=...]==a
que es innecesariamente largo). Sin embargo, hay otra opción:Lo mejor es que esto se puede usar para verificar si la entrada está ordenada inversamente para el mismo recuento de bytes:
Se puede guardar un byte más si a) sabemos que los elementos de la lista son distintos yb) conocemos un límite inferior entre 0 y 9 (inclusive; o límite superior para el orden inverso):
Para ver por qué esto funciona, consulte "Secuencias de argumentos" en la sugerencia vinculada en la parte superior.
fuente
##>0&@@a
. Similar para límite superior para ordenado.Repetir una cuerda
En lugar de
StringRepeat[str,n]
usar(0Range[n]+str)<>""
. O sistr
no depende de ningún argumento de ranura, aún mejor esArray[str&,n]<>""
según este consejo.fuente
StringRepeat[s,n+1]
usarArray[s&,n]<>s
(incluso cuando ya tienen+1
una variable, también).Table[str,n]<>""
Si necesita una lista de números ordenados al revés, no use
pero
para guardar seis bytes. Ordenar por un valor negativo también es útil para
SortBy
escenarios:fuente
-Sort@-x
?Puede pegar una expresión en la
Break
que puede guardar uno o dos caracteres. Ejemplo ( otros detalles no revelados para mayor claridad ):se puede convertir en
para salvar a un personaje Si la expresión en cuestión no tiene menor prioridad que la aplicación de función, incluso puede guardar otro carácter:
se puede convertir en
Aunque no está documentado, el argumento
Break
parece ser devuelto por el ciclo circundante, lo que puede conducir a ahorros aún mayores.fuente
Para eliminar todos los espacios en blanco de una cadena
s
, useEs decir, use
StringSplit
el valor predeterminado (dividido en componentes que no sean espacios en blanco) y simplemente vuelva a unirlos. Probablemente, el mismo sea el más corto si quieres deshacerte de cualquier otro personaje o subcadena:fuente
Alternativas a
Range
Una tarea muy común es aplicar algún tipo de función a todos los números del 1 al a
n
(generalmente se proporciona como entrada). Básicamente, hay 3 formas de hacer esto (usando una función de identidad sin nombre como ejemplo):Tiendo a ir por el primero (por cualquier razón), pero rara vez es la mejor opción.
Usando en su
Array
lugarEl ejemplo anterior muestra que usar
Array
tiene el mismo número de bytes. Sin embargo, tiene la ventaja de que es una sola expresión. En particular, si desea seguir procesando el resultado con una funciónf
, puede usar la notación de prefijo, que guarda un byte sobreRange
:Además, puede omitir paréntesis alrededor de su función sin nombre que podría haber necesitado
Range
, por ejemplo,Si no desea usarlo más (o con un operador que tiene menor prioridad), puede escribirlo
Array
en notación infija y también guardar un byte:Por lo tanto,
Array
es casi seguro mejor queRange
.Usando en su
Table
lugarAhora la tabla tiene que compensar 3 bytes, o al menos 2 cuando la notación infijada es una opción:
Cuando no use la notación infija,
Table
podría permitirle omitir paréntesis si su función consta de varias declaraciones:Esto aún es más largo, pero ofrece ahorros adicionales en el caso mencionado a continuación.
Los ahorros reales se
Table
deben al hecho de que no se debe descartar el nombre de la variable en ejecución. A menudo, habrá anidado funciones sin nombre donde desea utilizar la variable externa dentro de una de las funciones internas. Cuando eso sucede,Table
es más corto queRange
:No solo guarda los caracteres para asignarlos
i
, sino que también puede reducir la función a una sola declaración en el proceso, lo que le permite usar la notación infija encima. Como referencia,Array
también es más largo en este caso, pero aún más corto queRange
:¿Cuándo lo usarías realmente
Range
?Siempre que no necesite una llamada de función para procesar los valores, por ejemplo, cuando la asignación se puede realizar mediante una operación vectorizada. Por ejemplo:
Por supuesto, también es más corto si no desea asignar ninguna función, por ejemplo,
fuente
f/@Range[x]
regularmente ...Encontrar el número más pequeño que satisface una condición
Algunos constructos like
i=1;While[cond[i],i++]
están bien como están, pero hay una alternativa que es dos bytes más corta:El código anterior reemplaza repetidamente un número
i
pori+1
mientras cumple la condicióncond[i]
. En este caso,i
comienza en1
.Tenga en cuenta que el número máximo predeterminado de iteraciones es 2 ^ 16 (= 65536). Si necesita más iteraciones que eso,
While
sería mejor. (MaxIterations->∞
es demasiado largo)fuente
Abuso de evaluación de cortocircuito
A veces puede reemplazar
If
con un operador lógico.Por ejemplo, supongamos que desea hacer una función que verifique si un número es primo, e imprimir
2*(number) - 1
es si es verdadero:Es más corto si usas en su
&&
lugar:Incluso cuando tiene varias expresiones, aún guarda byte (s):
Puede usar
||
para casos en los que desea que la condición seaFalse
:Estos trucos funcionan porque los operadores lógicos pueden estar en cortocircuito ; el segundo argumento y, posteriormente, ni siquiera necesitan ser expresiones booleanas válidas.
Por supuesto, esto no funciona si necesita el valor de retorno de
If
o cuando necesita argumentos tanto verdaderos como falsosIf
.fuente
Aquí hay una lista con un montón de formularios de entrada del operador que pueden acortar muchas cosas. Algunos de estos se han mencionado en otras publicaciones, pero la lista es larga y siempre me sorprende encontrar algunas cosas nuevas allí:
fuente
Utilizando
Optional (:)
Optional (:)
se puede usar para expandir listas en reemplazos, sin tener que definir una regla separada para la expansión.Esta respuesta de mí y esta respuesta de @ngenisis son ejemplos.
Uso
El reemplazo anterior utiliza primero el patrón
{p___, a_, b_, q___}
y encuentra una coincidencia queb
cumple una determinada condición.Cuando no se encuentra dicha coincidencia, se omite
a_
y en su lugar se busca{p___, b_, q___}
.a
no está incluido en la búsqueda y se supone que tiene el valor0
.Tenga en cuenta que la segunda búsqueda de patrones solo funcionaría para
b
eso ocurre al comienzo de la lista; si unb
valor que satisface una condición está en el medio, entonces{p___, a_, b_, q___}
(que tiene una precedencia más alta) lo igualará en su lugar.El reemplazo es equivalente a anteponer a
0
cuando seb
produce una condición satisfactoria al comienzo de la lista. (es decir, no es necesario definir una regla separada{b_, q___} /; cond[b] :> ...
)fuente
Sepa cuándo (y cuándo no) usar argumentos de función pura con nombre
Para el golf de código, los
Function
argumentos puros se referencian más comúnmente usandoSlot
s; por ejemplo,#
para el primer argumento,#2
para el segundo, etc. (vea esta respuesta para más detalles).En muchos casos, querrás anidar
Function
s. Por ejemplo,1##&@@#&
es unFunction
que toma una lista como su primer argumento y genera el producto de sus elementos. Aquí está esa función enTreeForm
:Los argumentos pasados al nivel superior
Function
solo pueden llenarSlot
sysSlotSequence
presentes en el nivel superior, lo que en este caso significa queSlotSequence
en el interiorFunction
no habrá ninguna forma de acceder a los argumentos al nivel superiorFunction
.Sin embargo, en algunos casos, es posible que desee un
Function
anidado dentro de otroFunction
para poder hacer referencia a argumentos externosFunction
. Por ejemplo, es posible que desee algo comoArray[fun,...]&
, donde la funciónfun
depende de un argumento al nivel superiorFunction
. Para concretar, digamos quefun
debería dar al resto del cuadrado de su módulo de entrada la entrada al nivel superiorFunction
. Una forma de lograr esto es asignar el argumento de nivel superior a una variable:Dondequiera que
x
aparezca en lo internoFunction
Mod[#^2,x]&
, se referirá al primer argumento a lo externoFunction
, mientras que#
se referirá al primer argumento a lo internoFunction
. Un mejor enfoque es utilizar el hecho de queFunction
tiene una forma de dos argumentos donde el primer argumento es un símbolo o una lista de símbolos que representarán argumentos con nombre para elFunction
(en lugar deSlot
s sin nombre ). Esto termina ahorrándonos tres bytes en este caso:
es el carácter de uso privado de tres bytes queU+F4A1
representa el operador infijo binario\[Function]
. También puede usar la forma binaria deFunction
otroFunction
:Esto es equivalente a lo anterior. La razón es que, si está utilizando argumentos con nombre, se supone que
Slot
sySlotSequences
pertenecen al siguienteFunction
anterior que no utiliza argumentos con nombre.Ahora, solo porque podamos anidar
Function
s de esta manera, no significa que siempre debamos hacerlo. Por ejemplo, si quisiéramos seleccionar aquellos elementos de una lista que son menores que la entrada, podríamos sentir la tentación de hacer algo como lo siguiente:En realidad, sería más corto de usar
Cases
y evitaría la necesidad de un anidado porFunction
completo:fuente
Puede guardar un byte trabajando
Prepend
oPrependTo
:o
Desafortunadamente, esto no ayuda para los más comunes
Append
, que parece ser el equivalente más corto de unArray.push()
en otros idiomas.fuente
Mathematica 10.2:
BlockMap
esPartition
+Map
Este consejo también podría titularse, "Lea las notas de la versión, todas". (Como referencia, aquí están las notas de la versión 10.2 y aquí la versión 10.3 de hoy ).
De todos modos, incluso las versiones menores contienen una gran cantidad de nuevas características, y una de las más útiles (para jugar al golf) de 10.2 es la nueva
BlockMap
función. Básicamente se combinaPartition
yMap
es ideal para los golfistas, porquePartition
se usa con bastante frecuencia y es un nombre de función realmente molesto y largo. La nueva función no se acortaráPartition
por sí sola, pero cada vez que desee asignar una función a las particiones (lo que probablemente ocurre con mayor frecuencia), ahora puede guardar un byte o dos:Los ahorros se hacen aún mayores cuando la nueva posición de la función sin nombre le permite guardar algunos paréntesis:
Desafortunadamente, no tengo idea de por qué no agregué
BlockApply
mientras estaban en eso ...También tenga en cuenta que
BlockMap
no admite el cuarto parámetro con el que puede usarPartition
para obtener una lista cíclica:fuente
Almacenar funciones y expresiones en una variable
Si su respuesta termina usando las mismas funciones o expresiones varias veces, puede considerar almacenarlas en variables.
Si su expresión es longitud
l
y la usan
veces, normalmente usaríal * n
bytes.Sin embargo, si lo almacena en una variable de longitud 1, solo tomaría
3 + l + n
bytes (o2 + l + n
bytes, si asigna la variable donde no la necesitaráCompoundExpression (;)
o paréntesis).Por ejemplo, consideremos un problema simple, encontrar primos gemelos menores que N.
Se podría escribir esta solución de 54 bytes:
En este ejemplo, la función
PrimeQ
se usa tres veces.Al asignar
PrimeQ
un nombre de variable, el recuento de bytes se puede reducir. Los dos siguientes son 48 bytes (54 - 6 bytes):fuente
Para lograr una lista ascendente de clave-valor, use en
Sort
lugar deSortBy
Para listas como
list = {{1, "world"}, {0, "universe"}, {2, "country"}}
, las siguientes tres declaraciones son casi equivalentes.Combinar
Select
ySortBy
A veces necesitamos seleccionar entradas de un conjunto más grande y ordenarlas para encontrar un mínimo / máximo. En algunas circunstancias , dos operaciones podrían combinarse en una.
Por ejemplo, como mínimo, las siguientes dos declaraciones son casi equivalentes.
y
1/0
es decirComplexInfinity
, que es "más grande" que todos los números reales.Para una lista de valores clave, por ejemplo:
fuente
Aplanar un
Array
con##&
Cuando use una matriz multidimensional para calcular una lista de resultados que necesita ser aplanada, use
##&
como cuarto argumento. Esto reemplaza las cabezas de la matriz con##&
(equivalente aSequence
) en lugar deList
, por lo que el resultado final será un (plano)Sequence
de resultados.En dos dimensiones, compare
Por supuesto,
Join@@Array[f,dims]
sigue siendo 2 (o 3, si se puede usar la notación infija) bytes más cortos que{Array[f,dims,1,##&]}
.En tres o más dimensiones,
{Array[f,dims,origin,##&]}
siempre es más corto que la alternativa, incluso si el origen es 1.fuente
Valores predeterminados
Los valores predeterminados tratan los argumentos de patrones faltantes de manera eficiente. Por ejemplo, si queremos un patrón de coincidencia
Exp[c_*x]
en una regla para cualquier valor dec
, el ingenuousa muchos más bytes que si usamos el valor predeterminado para
c
cuando falta:El uso de un valor predeterminado, se indica con un punto después el patrón:
c_.
.Los valores predeterminados están asociados con las operaciones: en el ejemplo anterior, la operación está
Times
activadac_.*x
y, porc_
lo tanto, se toma un valor faltante del valor predeterminado asociado conTimes
, que es 1. ParaPlus
, el valor predeterminado es 0:Para
Power
exponentes, el valor predeterminado es 1:fuente