¿Qué consejos generales tienes para jugar al golf en Python? Estoy buscando ideas que se puedan aplicar a problemas de código de golf y que también sean al menos algo específicas para Python (por ejemplo, "eliminar comentarios" no es una respuesta).
Por favor, publique un consejo por respuesta.
Respuestas:
Usar en
a=b=c=0
lugar dea,b,c=0,0,0
.Usar en
a,b,c='123'
lugar dea,b,c='1','2','3'
.fuente
Los condicionales pueden ser largos. En algunos casos, puede reemplazar un condicional simple con
(a,b)[condition]
. Sicondition
es cierto, entoncesb
se devuelve.Comparar
A esto
fuente
a if a<b else b
ya<b and a or b
(lambda(): b, lambda(): a)[a < b]()
haz tu propio cortocircuito con lambdasP and A or B
cualquier A que débool(A)=False
. Pero(P and [A] or [B])[0]
hará el trabajo. Consulte diveintopython.net/power_of_introspection/and_or.html como referencia.Una gran cosa que hice una vez es:
en lugar de:
Los operadores de comparación de Python son geniales.
Usando que todo es comparable en Python 2, también puede evitar al
and
operador de esta manera. Por ejemplo, sia
,b
,c
yd
son números enteros,puede ser acortado por un personaje para:
Esto usa que cada lista es más grande que cualquier número entero.
Si
c
yd
son listas, esto se pone aún mejor:fuente
3>a>1<b<5
[$a => $b]->[$b <= $a]
:)if(a<b)+(c>d):foo()
*
. Unor
sería+
foo()if 3>a>1<b<5
Si usa una función incorporada repetidamente, podría ser más eficiente en espacio darle un nuevo nombre, si usa argumentos diferentes:
fuente
Algunas veces su código Python requiere que tenga 2 niveles de sangría. Lo obvio es usar uno y dos espacios para cada nivel de sangría.
Sin embargo, Python 2 considera que los caracteres de tabulación y espacio son diferentes niveles de sangría.
Esto significa que el primer nivel de sangría puede ser un espacio y el segundo puede ser un carácter de tabulación.
Por ejemplo:
¿Dónde
\t
está el carácter de tabulación?fuente
TabError: inconsistent use of tabs and spaces in indentation.
Use la sustitución de cadenas y
exec
para manejar palabras clave largas comolambda
esa se repiten a menudo en su código.La cadena de destino es muy a menudo
'lambda '
, que tiene 7 bytes de longitud. Suponga que su fragmento de código contienen
ocurrencias de'lambda '
y tiene unas
longitud de bytes. Entonces:plain
opción tiene unas
longitud de bytes.replace
opción tiene unas - 6n + 29
longitud de bytes.%
opción tiene unas - 5n + 22 + len(str(n))
longitud de bytes.De una gráfica de bytes guardados
plain
para estas tres opciones, podemos ver que:exec"..."%(('lambda ',)*5)
ahorra 2 bytes y es su mejor opción.exec"...".replace('`','lambda ')
es su mejor opción.Para otros casos, puede indexar la siguiente tabla:
Por ejemplo, si la cadena
lambda x,y:
(longitud 11) aparece 3 veces en su código, es mejor que escribaexec"..."%(('lambda x,y:',)*3)
.fuente
replace
es enorme.=>
es solo la cadena= lambda
. Por ejemplo,f=>:0
seríaf = lambda: 0
.Use el corte extendido para seleccionar una cadena entre muchas
vs
En este caso booleano de dos cuerdas, también se puede escribir
para
A diferencia del intercalado, esto funciona para cadenas de cualquier longitud, pero puede tener problemas de precedencia de operador si, en
b
cambio, es una expresión.fuente
for x in ("foo","bar","baz"): print x
x
. La parte de golf es el"fbboaaorz"[x::3]
vs["foo","bar","baz"][x]
Cómox
se deriva el valor sería otra parte de su solución de golf.Use
`n`
para convertir un entero en una cadena en lugar de usarstr(n)
:fuente
Almacenar tablas de búsqueda como números mágicos
Supongamos que desea codificar una tabla de búsqueda booleana, como cuál de los primeros doce números en inglés contiene un
n
.Luego, puede implementar esta tabla de búsqueda de forma concisa como:
con el resultado
0
o1
ser igualFalse
aTrue
.La idea es que el número mágico almacena la tabla como una cadena de bits
bin(3714)
=0b111010000010
, con eln
enésimo dígito (desde el final) correspondiente a lan
entrada de la tabla th. Accedemos a lan
XX entrada por bitshifting el númeron
de espacios a la derecha y tomar el último dígito&1
.Este método de almacenamiento es muy eficiente. Compara con las alternativas
Puede hacer que su tabla de búsqueda almacene entradas multibit que se pueden extraer como
para extraer el bloque de cuatro bits relevante.
fuente
Contraer dos bucles numéricos en uno
Digamos que estás iterando sobre las celdas de una
m*n
cuadrícula. En lugar de dosfor
bucles anidados , uno para la fila y una de las columnas, generalmente es más corto usar un solo bucle para iterar sobre lasm*n
celdas de la cuadrícula. Puede extraer la fila y la columna de la celda dentro del bucle.Código original:
Código de golf:
En efecto, estás iterando sobre el producto cartesiano de los dos rangos, codificando el par
(i,j)
comox=i*n+j
. Ha guardado unarange
llamada costosa y un nivel de sangría dentro del bucle. El orden de iteración no ha cambiado.Use en
//
lugar de/
en Python 3. Si se refierei
yj
muchas veces, puede ser más rápido asignar sus valoresi=k/n
,j=k%n
dentro del ciclo.fuente
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
bucles: repl.it/EHwaitertools.product
puede ser mucho más conciso que los bucles anidados, especialmente al generar productos cartesianos.a1, a2, b1, b2
son ejemplos del producto cartesiano de'ab'
y'12'
A menos que el siguiente token comience con
e
oE
. Puede eliminar el espacio después de un número.Por ejemplo:
Se convierte en:
Usar esto en declaraciones complicadas de una línea puede ahorrar bastantes caracteres.
EDITAR: como señaló @marcog,
4or a
funcionará, pero noa or4
ya que esto se confunde con un nombre de variable.fuente
if(i,j)==(4,4):
es aún más corto y en este caso especialif i==j==4:
4or a
funciona, pero noa or4
0or
tampoco funciona (0o
es un prefijo para números octales).0 or x
que siempre va a volverx
. También podría cortar el0 or
.0or
Sin embargo, está bien como parte de un número más largo.10 or x
es equivalente a10or x
.Por entero
n
, puedes escribirn+1
como-~n
n-1
como~-n
porque el cambio de bit
~x
es igual-1-x
. Utiliza el mismo número de caracteres, pero puede cortar espacios o parees indirectamente para la precedencia del operador.Comparar:
Los operadores
~
y unario-
son más altas que prevalecen*
,/
,%
, a diferencia binaria+
.fuente
-~-x
ahorra uno contra bytes(1-x)
.a+b+1
se puede escribir de manera más concisa comoa-~b
.n-i-1
es juston+~i
.Una buena manera de convertir un iterable a la lista en Python 3 :
imagina que tienes algunos iterables, como
Pero necesitas una lista:
Es muy útil hacer una lista de caracteres de una cadena
fuente
*s,='abcde'
y luegos
bloquea mi python3 interactivo con un segfault :([*'abcde']
.En lugar de
range(x)
, puede usar el*
operador en una lista de cualquier cosa, si realmente no necesita usar el valor dei
:Opuesto a
Si necesita hacer esto más de dos veces, puede asignar cualquier iterable a una variable y multiplicar esa variable por el rango que desee:
Nota : esto suele ser más largo que
exec"pass;"*8
, por lo que este truco solo debe usarse cuando no es una opción.fuente
[1]*8
es más corto querange(8)
, también puede ahorrar un espacio porquefor i in[...
es legal mientrasfor i in range...
que no lo es".exec"pass;"*8
Es significativamente más corto.r=1
,r*8
es 8, y no puede iterar a través de un número. Supongo que quisiste decirr=[1]
Puedes usar la vieja carita feliz alienígena para invertir las secuencias:
fuente
Desempaquetado iterable extendido ("Asignación destacada", solo Python 3)
La mejor manera de explicar esto es a través de un ejemplo:
Ya hemos visto un uso para esto: convertir un iterable en una lista en Python 3 :
Aquí hay algunos usos más.
Obtener el último elemento de una lista
En algunas situaciones, esto también se puede usar para obtener el primer elemento para guardar en los padres:
Asignación de una lista vacía y otras variables.
Eliminar el primer o el último elemento de una lista no vacía
Estos son más cortos que las alternativas
L=L[1:]
yL.pop()
. El resultado también se puede guardar en una lista diferente.Consejos cortesía de @grc
fuente
a=1;L=[]
muchas veces. Es sorprendente que puedas guardar caracteres en algo tan sencillo como esto.a,*L=1,
), pero aún ahorra un carácter :)a,*_,b=L
establecer literales en Python2.7
Puede escribir conjuntos como este
S={1,2,3}
Esto también significa que puede verificar la membresía usando en{e}&S
lugar de loe in S
que guarda un carácter.fuente
if
s ya que no hay espacios (if{e}&S:
)not in
por{e}-S
ese trucoDurante siglos me molestó que no pudiera pensar en una forma corta de obtener el alfabeto completo. Si usa lo
range
suficiente queR=range
vale la pena tener en su programa, entonceses más corto que el ingenuo
, pero por lo demás es más largo por un solo personaje. Me persiguió que el inteligente que requería un cierto conocimiento de los valores ascii terminara siendo más detallado que simplemente escribir todas las letras.
Hasta que vi esta respuesta para el alfabeto de mi hija . No puedo seguir el historial de edición lo suficientemente bien como para descubrir si este genio fue obra del OP o si fue una sugerencia de un comentarista, pero esta es (creo) la forma más corta de crear un iterable de las 26 letras. en el alfabeto romano
Si el caso no importa, puedes quitar otro personaje usando mayúsculas:
Uso
map
demasiado, no sé cómo esto nunca se me ocurrió.fuente
string.lowercase
: para eso está.ord('z')
)? Además de ser de la misma longitud ... Además, si necesita alfanuméricos, reemplácelosstr.isalpha
en la versión de @ quintopia constr.isalnum
. (Pero si solo necesita un caso, la cadena completa de 36 caracteres no es más larga quefilter(str.isalnum,map(chr,range(90)))
).R
, mi versión es más corta que la original:'%c'*26%tuple(R(97,123))
(solo 24 caracteres) si la deletrearange
es tan larga como el alfabeto - la versión en mayúscula es más cortaAunque python no tiene declaraciones de cambio, puede emularlas con diccionarios. Por ejemplo, si desea un interruptor como este:
Podría usar
if
declaraciones, o podría usar esto:o esto:
lo cual es mejor si todas las rutas de código son funciones con los mismos parámetros.
Para admitir un valor predeterminado, haga esto:
(o esto:)
Otra ventaja de esto es que si tiene redundancias, puede agregarlas después del final del diccionario:
Y si solo desea utilizar un interruptor para devolver un valor:
Podrías hacer esto:
fuente
dict(s1=v1,s2=v2,...,sn=vn)
lugar de{'s1':v1,'s2':v2,...,'sn':vn}
guardar 2 * n-4 bytes y es mejor si n> = 3Cuando tiene dos valores booleanos,
a
yb
, si se quiere averiguar si ambosa
yb
son verdaderas, utilizar*
en lugar deand
:vs
si cualquiera de los valores es falso, se evaluará como
0
en esa declaración, y un valor entero solo es verdadero si no es cero.fuente
&
:a=b=False
,a&b
+
paraor
si se puede garantizara != -b
|
Funciona en todas las situaciones.*
en lugar deand
/&&
guarda algunos bytes en muchos idiomas.Explotar representaciones de cadenas de Python 2
Python 2 le permite convertir un objeto
x
a su representación de cadena`x`
a un costo de solo 2 caracteres. Use esto para tareas que son más fáciles de hacer en la cadena del objeto que en el objeto mismo.Unir personajes
Dada una lista de caracteres
l=['a','b','c']
, uno puede producir''.join(l)
como`l`[2::5]
, lo que guarda un byte.La razón es que
`l`
es"['a', 'b', 'c']"
(con espacios), por lo que uno puede extraer las letras con un corte de lista, comenzando ese segundo carácter indexado a ceroa
y tomando cada quinto carácter desde allí. Esto no funciona para unir cadenas de caracteres múltiples o caracteres de escape representados como'\n'
.Dígitos concatenados
Del mismo modo, dada una lista no vacía de dígitos como
l=[0,3,5]
, uno puede concatenarlos en una cadena'035'
como`l`[1::3]
.Esto ahorra hacer algo como
map(str,l)
. Tenga en cuenta que deben ser de un solo dígito y no pueden tener flotantes como1.0
mezclados. Además, esto falla en la lista vacía, produciendo]
.Verifica si hay negativos
Ahora, para una tarea sin cadenas. Suponga que tiene una lista
l
de números reales y quiere probar si contiene números negativos, produciendo un Booleano.Tu puedes hacer
que comprueba si hay un signo negativo en el representante de la cadena. Este más corto que cualquiera de
Por el segundo,
min(l)<0
fallaría en la lista vacía, por lo que debe cubrirse.fuente
str(l)[2::5]
es 12 bytes, frente a 19 para''.join(map(str,l))
. Una situación real en la que esto surgió (dondel
había una declaración de generador, no una lista) me salvó solo un byte ... ¡que todavía vale la pena!Se puede hacer una función de una línea con lambda:
se puede convertir a (tenga en cuenta el espacio faltante
3and
y10or
)fuente
c=lambda a:a+[-5,10][a<3]
. el y / o el truco es más útil cuando depende del comportamiento delelse:
puede descartarse ya quereturn
detiene la ejecución de la función, por lo que todo lo que sigue solo se ejecuta si laif
condición falla, es decir, si laelse
condición es verdadera. Porelse
lo tanto, se puede omitir con seguridad. (Explicado en detalles para los neófitos)c=lambda a:a-5+15*(a<3)
los bucles de hasta 4 elementos pueden ser mejores para suministrar una tupla en lugar de usar el rango
vs
fuente
Techo y piso
Si alguna vez desea obtener el resultado redondeado para una división, al igual que lo haría con el
//
piso, puede usarmath.ceil(3/2)
para 15 o el más corto-(-3//2)
para 8 bytes.fuente
n//1+1
lugar de ceil pero significa ceil (n) = n + 1 pero debería funcionar para todos los valores no enterosround(x)
es(x+.5)//1
, +1 byte pero este último comienza con a(
, y six
es una suma que consiste en una constante, puede ser útil.Usar en
+=
lugar deappend
yextend
se puede acortar a:
B,
aquí crea una tupla de un elemento que se puede usar para extenderA
al igual que[B]
enA+=[B]
.se puede acortar a:
fuente
return 0
oreturn 1
es equivalente areturn False
oreturn True
.-x
en lugar dex*-1
.--8.32
en lugar de-8.32*-1
. O simplemente8.32
...A+=B
B
es atuple
.Elegir uno de dos números en función de una condición
Usted ya sabe usar la selección de la lista
[x,y][b]
con un valor booleanob
para la expresión ternariay if b else x
. Las variablesx
,y
yb
también pueden ser expresiones, aunque tenga en cuenta que ambasx
yy
se evalúan incluso cuando no se seleccionan.Aquí hay algunas optimizaciones potenciales cuando
x
yy
son números.[0,y][b] -> y*b
[1,y][b] -> y**b
[x,1][b] -> b or x
[x,x+1][b] -> x+b
[x,x-1][b] -> x-b
[1,-1][b] -> 1|-b
[x,~x][b] -> x^-b
[x,y][b] -> x+z*b
(oy-z*b
), donde z = yx.También puede cambiar
x
yy
si puede reescribirb
para ser su negación.fuente
Use ~ para indexar desde el final de una lista
Si
L
es una lista, useL[~i]
para obtener eli
'th elemento desde atrás.Este es el
i
'th elemento del reverso deL
. El complemento de bits~i
es igual-i-1
y, por lo tanto, corrige el error off-by-oneL[-i]
.fuente
PEP448 - Generalizaciones adicionales de desempaque
Con el lanzamiento de Python 3.5 , la manipulación de listas, tuplas, conjuntos y dictos se volvió más golfista.
Convertir un iterable en un conjunto / lista
Compara los pares:
¡Mucho más corto! Sin embargo, tenga en cuenta que si solo desea convertir algo en una lista y asignarlo a una variable, el desempaquetado iterativo extendido normal es más corto:
Una sintaxis similar funciona para las tuplas:
que es como desempaquetar iterable extendido, pero con el asterisco y la coma en el otro lado.
Unirse a listas / tuplas
Desempacar es un poco más corto que la concatenación si necesita agregar una lista / tupla a ambos lados:
Imprimir el contenido de múltiples listas
Esto no se limita a
print
, pero definitivamente es de donde vendrá la mayor parte del kilometraje. PEP448 ahora permite el desempaque múltiple, así:Actualización de múltiples elementos del diccionario
Esto probablemente no sucederá muy a menudo, pero la sintaxis se puede usar para ahorrar en la actualización de diccionarios si está actualizando al menos tres elementos:
Esto básicamente niega cualquier necesidad de
dict.update
.fuente
Cambiar
import *
aimport*
Si no has escuchado,
import*
guarda caracteres!es solo 1 carácter más largo
import math as m
y puede eliminar todas las instancias dem.
¡Incluso el uso de una sola vez es un ahorro!
fuente
si el valor de i es inútil:
o
fuente
for i in[0]*x:s+=input()
para ahorrar otro espacio. Además, puede eliminar el espacio entre el ejecutivo y la primera comilla para obtenerexec's+=input();'*x
for i in[0]*x:s+=input()