Sto giocando a code-golf correttamente?


12

Sono curioso di sapere se sto giocando a Code Golf. Mi sono posto la sfida di trasformare un piccolo programma di hashing in un'unica istruzione in Python. Ho iniziato 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()

Ho quindi reso la funzione ricorsiva:

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))

Ho provato ad accorciarlo con un lambda per ripetere il codice (non ha funzionato):

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)

Alla fine ho finito 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))

Volevo che il programma fosse una dichiarazione, quindi per prima cosa ho escogitato:

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")

E infine ho finito 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")())

È così che vengono risolti i problemi di codegolf? Non ho mai fatto questo genere di cose, quindi in questo momento voglio solo sapere se lo sto facendo bene.

Emendamento: questo programma fa tutto il lavoro per te; quindi farò qui riferimento alla funzione: Come input, il programma accetta tutte le permutazioni di una determinata stringa; qui la stringa è composta da nove caratteri scelti casualmente ascii_lowercase. L'output è una stringa leggibile dall'uomo che definisce se il risultato di ciascuna permutazione della stringa data è un duplicato di un altro risultato per una stringa diversa. Se non ci sono duplicati per tutte le permutazioni, il programma indica il successo. Nove personaggi sono stati scelti come la più grande lunghezza di personaggi facilmente calcolati ripetutamente sulla mia scatola.

Emendamento II Come sottolineato da un lettore studioso, lo scopo previsto descritto non è ottenuto attraverso il codice allegato. Il caso di prova è ovviamente inadeguato.


3
Sembra una buona domanda, e sono felice di vedere che hai mostrato il tuo processo di golf in dettaglio. Ma non so cosa intendi con programma "hashing". Dovresti pubblicare una specifica che spieghi come deve essere preso l'input, come deve essere dato l'output e quale relazione deve avere l'output con l'input.
xnor

@xnor è sufficiente?
Motoku,

Per il golf del codice, dovresti assolutamente rimuovere alcuni degli spazi opzionali. Inoltre, usa invece Python 2, poiché la stampa è più breve. print"x"invece diprint("x")
mbomb007,

E utilizzare una comprensione dell'elenco anziché list()?
mbomb007,

3
Il tuo processo sembra a posto. Inizia con un programma, abbreviato in prova / errore. Ottieni più esperienza e consulta i suggerimenti su Python e farai grandi cose in pochissimo tempo.
Geobits il

Risposte:


11

Non esiste un modo "giusto" per giocare a golf. Hai fatto bene e il processo che hai usato è abbastanza standard. Trasformare il programma in una dichiarazione non è di solito un requisito però.

Se aiuta, ecco come approccerei il golf nel tuo programma ...

Nella funzione di hashing, l'istruzione for può essere sostituita con una somma:

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

Questa può quindi essere definita come una funzione lambda:

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

E ora rimuoviamo spazi e parentesi non necessari:

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

Come ha sottolineato Sp3000, questo può essere ulteriormente abbreviato con l'enumerato:

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

Passando alla funzione di test, uniamo le sue prime due righe:

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

Poiché entrambe le funzioni vengono utilizzate una sola volta, possiamo spostare tutto in linea:

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

Questo è più breve come comprensione dell'elenco:

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

Successivamente, gli assegniamo un nome più breve e rimuoviamo nuovamente gli spazi non necessari:

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

L'istruzione if può essere spostata all'interno della funzione di stampa:

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

Tuttavia, di solito è più breve da usare e / o:

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

Dal momento len(x)che non cambia, possiamo calcolare e codificare il suo valore:

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

Dopo aver rimosso gli spazi non necessari e aver cambiato il confronto, otteniamo:

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

Questo ci consente di spostare tutto in un'unica istruzione:

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...')

E ora possiamo usare invece una comprensione set:

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...')

Il risultato è 210 byte, escluse le importazioni. Il prossimo passo sarebbe probabilmente quello di ridurre le importazioni o le lunghe stringhe.


7
Stranamente, penso che enumeratesia più breve:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000,

@ Sp3000 oh bello! Ogni builtin ha il suo giorno: D
grc
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.