Bin ich richtig Code-Golfen?

12

Ich bin neugierig, ob ich richtig Code Golf spiele. Ich habe es mir zur Aufgabe gemacht, ein kleines Hashing-Programm in Python in eine einzige Anweisung umzuwandeln. Ich habe angefangen mit:

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

Ich habe dann die Funktion rekursiv gemacht:

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

Ich habe versucht, es mit einem Lambda zu verkürzen, um den Code zu wiederholen (es hat nicht funktioniert):

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)

Am Ende hatte ich ein 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))

Ich wollte, dass das Programm eine Aussage ist, also kam ich zuerst auf:

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

Und zum Schluss kam ich mit:

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

Werden so Codegolf-Probleme gelöst? Ich habe so etwas noch nie gemacht, also möchte ich jetzt nur wissen, ob ich es richtig mache.

Änderung: Dieses Programm erledigt die ganze Arbeit für Sie; Ich werde hier also auf die Funktion verweisen: Als Eingabe nimmt das Programm alle Permutationen eines gegebenen Strings auf; Hier besteht die Zeichenfolge aus neun zufällig ausgewählten Zeichen ascii_lowercase. Die Ausgabe ist eine vom Menschen lesbare Zeichenfolge, die definiert, ob das Ergebnis jeder Permutation der angegebenen Zeichenfolge ein Duplikat eines anderen Ergebnisses für eine andere Zeichenfolge ist. Wenn für alle Permutationen keine Duplikate vorhanden sind, zeigt das Programm den Erfolg an. Neun Zeichen wurden als die größte Anzahl von Zeichen ausgewählt, die auf meiner Box wiederholt berechnet wurden.

Änderungsantrag II Wie ein aufmerksamer Leser hervorhebt, wird der beschriebene Verwendungszweck nicht durch den beigefügten Code erreicht. Der Testfall ist offensichtlich unzureichend.

Motoku
quelle
3
Dies scheint eine gute Frage zu sein, und ich freue mich, dass Sie Ihren Golfprozess im Detail gezeigt haben. Aber ich weiß nicht, was Sie mit "Hashing" -Programm meinen. Sie sollten eine Spezifikation veröffentlichen, in der erläutert wird, wie die Eingabe erfolgen soll, wie die Ausgabe erfolgen soll und in welchem ​​Verhältnis die Ausgabe zur Eingabe stehen muss.
26.
@xnor reicht das aus?
Motoku
Für Code-Golf sollten Sie auf jeden Fall einige dieser optionalen Leerzeichen entfernen. Verwenden Sie stattdessen auch Python 2, da der Druckvorgang kürzer ist. print"x"anstelle vonprint("x")
mbomb007
Und stattdessen ein Listenverständnis verwenden list()?
mbomb007
3
Ihr Prozess scheint in Ordnung zu sein. Beginnen Sie mit einem Programm und kürzen Sie es durch Ausprobieren. Holen Sie sich mehr Erfahrung und stöbern Sie in den Python-Tipps, und Sie werden in kürzester Zeit großartig abschneiden.
Geobits

Antworten:

11

Es gibt keinen "richtigen" Weg zum Golf. Du hast es gut gemacht und der Prozess, den du benutzt hast, ist ziemlich normal. Es ist jedoch normalerweise nicht erforderlich, das Programm in eine einzige Anweisung umzuwandeln.

Wenn es hilft, würde ich wie folgt vorgehen, um Ihr Programm abzurunden ...

In der Hashing-Funktion kann die for-Anweisung durch eine Summe ersetzt werden:

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

Dies kann dann als Lambda-Funktion definiert werden:

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

Und jetzt entfernen wir unnötige Leerzeichen und Klammern:

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

Wie Sp3000 hervorhob, kann dies mit enumerate weiter verkürzt werden:

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

Bei der Testfunktion werden die ersten beiden Zeilen zusammengeführt:

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

Da beide Funktionen nur einmal verwendet werden, können wir alles inline verschieben:

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

Dies ist als Listenverständnis kürzer:

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

Als nächstes geben wir ihm einen kürzeren Namen und entfernen wieder unnötige Leerzeichen:

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

Die if-Anweisung kann innerhalb der Druckfunktion verschoben werden:

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

Normalerweise ist es jedoch kürzer und / oder:

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

Da len(x)sich nichts ändert, können wir seinen Wert berechnen und fest codieren:

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

Nach dem Entfernen unnötiger Leerzeichen und dem Umschalten des Vergleichs erhalten wir:

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

So können wir alles in einer Anweisung zusammenfassen:

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

Und jetzt können wir stattdessen ein Mengenverständnis verwenden:

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

Das Ergebnis ist 210 Byte, ohne Importe. Der nächste Schritt wäre wahrscheinlich, die Importe oder die langen Saiten herunterzuspielen.

grc
quelle
7
Komischerweise denke ich enumerateist kürzer:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000
@ Sp3000 oh schön! Jeder eingebaute hat seinen Tag: D
grc