Suis-je en train de jouer au golf correctement?

12

Je suis curieux de savoir si je joue correctement au Code Golf. Je me suis fixé le défi de transformer un petit programme de hachage en une seule instruction en Python. J'ai commencé avec:

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

J'ai ensuite rendu la fonction récursive:

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

J'ai essayé de le raccourcir avec un lambda pour répéter le code (cela n'a pas fonctionné):

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)

Enfin je me suis retrouvé avec une 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))

Je voulais que le programme soit une déclaration, alors j'ai d'abord trouvé:

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

Et enfin je me suis retrouvé avec:

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

Est-ce ainsi que les problèmes de codegolf sont résolus? Je n'ai jamais vraiment fait ce genre de choses, donc en ce moment je veux juste savoir si je le fais bien.

Amendement: ce programme fait tout le travail pour vous; je vais donc ici faire référence à la fonction: En entrée, le programme accepte toutes les permutations d'une chaîne donnée; ici, la chaîne est composée de neuf caractères choisis au hasard ascii_lowercase. La sortie est une chaîne lisible par l'homme définissant si le résultat de chaque permutation de la chaîne donnée est un doublon d'un autre résultat pour une chaîne différente. S'il n'y a pas de doublons pour toutes les permutations, le programme indique le succès. Neuf caractères ont été choisis comme étant la plus grande longueur de caractères facilement calculée à plusieurs reprises sur ma boîte.

Amendement II Comme l'a souligné un lecteur studieux, l'objectif visé décrit n'est pas obtenu par le biais du code d'accompagnement. Le cas de test est évidemment insuffisant.

motoku
la source
3
Cela ressemble à une bonne question de conseils, et je suis heureux de voir que vous avez montré en détail votre processus de golf. Mais je ne sais pas ce que vous entendez par programme de «hachage». Vous devez publier une spécification qui explique comment l'entrée doit être prise, comment la sortie doit être donnée et quelle relation la sortie doit avoir avec l'entrée.
xnor
@xnor cela suffit-il?
motoku
Pour le golf de code, vous devez absolument supprimer un peu plus de ces espaces facultatifs. Utilisez également Python 2 à la place, car l'impression est plus courte. print"x"au lieu deprint("x")
mbomb007
Et utilisez une compréhension de liste au lieu de list()?
mbomb007
3
Votre processus semble bien. Commencez avec un programme, raccourci par essai / erreur. Obtenez plus d'expérience et parcourez les conseils python et vous ferez très bien en peu de temps.
Geobits

Réponses:

11

Il n'y a pas de «bonne» façon de jouer au golf. Vous avez bien fait et le processus que vous avez utilisé est assez standard. Faire du programme en une seule déclaration n'est généralement pas une exigence cependant.

Si cela peut vous aider, voici comment j'aborderais le golf avec votre programme ...

Dans la fonction de hachage, l'instruction for peut être remplacée par une somme:

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

Cela peut alors être défini comme une fonction lambda:

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

Et maintenant, nous supprimons les espaces et les crochets inutiles:

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

Comme l'a souligné Sp3000, cela peut être encore raccourci avec énumérer:

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

Passant à la fonction de test, nous fusionnons ses deux premières lignes:

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

Étant donné que les deux fonctions ne sont utilisées qu'une seule fois, nous pouvons tout déplacer en ligne:

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

Ceci est plus court pour une compréhension de liste:

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

Ensuite, nous lui donnons un nom plus court et supprimons à nouveau les espaces inutiles:

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

L'instruction if peut être déplacée à l'intérieur de la fonction d'impression:

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

Cependant, il est généralement plus court à utiliser et / ou:

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

Puisque len(x)ne change pas, nous pouvons calculer et coder en dur sa valeur:

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

Après avoir supprimé les espaces inutiles et changé la comparaison, nous obtenons:

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

Cela nous permet de tout déplacer dans une seule déclaration:

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

Et maintenant, nous pouvons utiliser une compréhension d'ensemble à la place:

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

Le résultat est de 210 octets, hors importations. La prochaine étape serait probablement de baisser les importations ou les longues chaînes.

grc
la source
7
Curieusement, je pense que enumeratec'est plus court:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000
@ Sp3000 oh nice! Chaque buildin a son jour: D
grc