¿Estoy jugando al golf correctamente?

12

Tengo curiosidad si estoy Code Golfing correctamente. Me propuse el desafío de hacer un pequeño programa de hash en una sola declaración en Python. Primero comencé con:

from itertools import permutations
from string import ascii_lowercase
from random import sample

def test():
    chars = sample(ascii_lowercase, 9)
    sums = list(map(h, permutations(chars)))
    if len(set(sums)) == len(sums):
       print("unique results for permutations of given string")
    else:
       print("duplicate entries present in test results")

def h(s):
    r = 0
    for i in range(len(s)):
        r += ord(s[i]) << (i * len(s))
    return r

test()

Luego hice la función recursiva:

def h(s, i=0):
    if i < len(s) - 1: return h(s, i+1) + ord(s[i]) << (i * len(s))
    else: return ord(s[i]) << (i * len(s))

Intenté acortarlo con un lambda para repetir el código (no funcionó):

def h(s, i=0, f=lambda s,i: ord(s[i]) << (i * len(s))):
    if i < len(s) - 1: return h(s, i+1) + f(s,i)
    else: return f(s,i)

Finalmente terminé con una lambda:

h=lambda s,i=0:h(s,i+1)+ord(s[i])<<(i*len(s))if i<len(s)-1 else ord(s[i])<<(i*len(s))

Quería que el programa fuera una declaración, así que primero se me ocurrió:

def test():
    chars = sample(ascii_lowercase, 9)
    sums = list(map((lambda s,i=0,f=lambda s,i,f:f(s,i+1,f)+ord(s[i])<<(i*len(s))if i<len(s)-1 else ord(s[i])<<(i*len(s)):f(s,i,f)), permutations(chars)))
    if len(set(sums)) == len(sums):
       print("unique results for permutations of given string")
    else:
       print("duplicate entries present in test results")

Y finalmente terminé con:

print((lambda x=list(map((lambda s,i=0,f=lambda s,i,f:f(s,i+1,f)+ord(s[i])<<(i*len(s))if i<len(s)-1 else ord(s[i])<<(i*len(s)):f(s,i,f)), permutations(sample(ascii_lowercase, 9)))): "unique results for permutations of given string" if len(set(x)) == len(x) else "duplicate entries present in test results")())

¿Es así como se resuelven los problemas de codegolf? Realmente nunca he hecho este tipo de cosas, así que ahora solo quiero saber si lo estoy haciendo bien.

Enmienda: este programa hace todo el trabajo por usted; así que aquí me referiré a la función: como entrada, el programa toma todas las permutaciones de una cadena dada; aquí la cadena tiene nueve caracteres elegidos al azar ascii_lowercase. La salida es una cadena legible por humanos que define si el resultado de cada permutación de la cadena dada es un duplicado de otro resultado para una cadena diferente. Si no hay duplicados para todas las permutaciones, el programa indica éxito. Se seleccionaron nueve caracteres como la mayor longitud de caracteres que se calcularon fácilmente repetidamente en mi caja.

Enmienda II Como lo señaló un lector estudioso, el propósito previsto descrito no se obtiene a través del código adjunto. El caso de prueba es obviamente inadecuado.

motoku
fuente
3
Esta parece una buena pregunta de consejos, y me complace ver que ha mostrado su proceso de golf en detalle. Pero no sé a qué te refieres con el programa "hash". Debe publicar una especificación que explique cómo se debe tomar la entrada, cómo se debe dar la salida y qué relación debe tener la salida con la entrada.
xnor
@xnor ¿eso es suficiente?
motoku
Para el golf de código, definitivamente debe eliminar algunos más de esos espacios opcionales. Además, use Python 2, ya que la impresión es más corta. print"x"en lugar deprint("x")
mbomb007
¿Y usar una lista de comprensión en lugar de list()?
mbomb007
3
Tu proceso parece estar bien. Comience con un programa, acorte por prueba / error. Obtenga más experiencia y explore los consejos de Python y lo hará muy bien en poco tiempo.
Geobits

Respuestas:

11

No hay una forma "correcta" de jugar al golf. Lo has hecho bien y el proceso que has utilizado es bastante estándar. Sin embargo, convertir el programa en una declaración no suele ser un requisito.

Si ayuda, así es como abordaría el golf en su programa ...

En la función hash, la instrucción for se puede reemplazar con una suma:

def h(s):
    r = 0
    r = sum(ord(s[i]) << (i * len(s)) for i in range(len(s)))
    return r

Esto se puede definir como una función lambda:

h = lambda s: sum(ord(s[i]) << (i * len(s)) for i in range(len(s)))

Y ahora eliminamos espacios y corchetes innecesarios:

h=lambda s:sum(ord(s[i])<<i*len(s)for i in range(len(s)))

Como señaló Sp3000, esto se puede acortar aún más con enumerate:

h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))

Pasando a la función de prueba, fusionamos sus dos primeras líneas:

def test():
    sums = list(map(h, permutations(sample(ascii_lowercase, 9))))
    ...

Como ambas funciones solo se usan una vez, podemos mover todo en línea:

sums = list(map(lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s)), permutations(sample(ascii_lowercase, 9))))
...

Esto es más corto como una lista de comprensión:

sums = [sum(ord(x)<<i*len(s)for i,x in enumerate(s)) for s in permutations(sample(ascii_lowercase, 9))]

A continuación, le damos un nombre más corto y eliminamos espacios innecesarios nuevamente:

x=[sum(ord(x)<<i*len(s)for i,x in enumerate(s))for s in permutations(sample(ascii_lowercase,9))]

La instrucción if se puede mover dentro de la función de impresión:

print('unique...' if len(set(x)) == len(x) else 'duplicate...')

Sin embargo, generalmente es más corto de usar y / o:

print(len(set(x)) == len(x) and 'unique...' or 'duplicate...')

Como len(x)no cambia, podemos calcular y codificar su valor:

print(len(set(x)) == 362880 and 'unique...' or 'duplicate...')

Después de eliminar espacios innecesarios y cambiar la comparación, obtenemos:

print(len(set(x))<362880and'duplicate...'or'unique...')

Esto nos permite mover todo a una declaración:

print(len(set([sum(ord(x)<<i*len(s)for i,x in enumerate(s))for s in permutations(sample(ascii_lowercase,9))]))<362880and'duplicate...'or'unique...')

Y ahora podemos usar un conjunto de comprensión en su lugar:

print(len({sum(ord(x)<<i*len(s)for i,x in enumerate(s))for s in permutations(sample(ascii_lowercase,9))})<362880and'duplicate...'or'unique...')

El resultado es 210 bytes, excluidas las importaciones. El siguiente paso probablemente sería reducir las importaciones o las largas cadenas.

grc
fuente
77
Curiosamente, creo que enumeratees más corto:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000
@ Sp3000 ¡qué bien! Cada edificio tiene su día: D
grc