Estou praticando golfe de código corretamente?

12

Estou curioso para saber se eu sou o Code Golfing corretamente. Eu propus o desafio de transformar um pequeno programa de hash em uma única declaração no Python. Comecei com:

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

Eu então fiz a função 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))

Tentei encurtá-lo com um lambda para repetir o código (não funcionou):

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 acabei com uma 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))

Eu queria que o programa fosse uma declaração, então, primeiro, criei:

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, finalmente, acabei com:

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

É assim que os problemas do codegolf são resolvidos? Eu nunca realmente fiz esse tipo de coisa, então agora eu só quero saber se estou fazendo certo.

Alteração: Este programa faz todo o trabalho para você; portanto, vou me referir à função: Como entrada, o programa recebe todas as permutações de uma determinada string; aqui a string tem nove caracteres escolhidos aleatoriamente ascii_lowercase. A saída é uma sequência legível por humanos que define se o resultado de cada permutação da sequência fornecida é uma duplicata de outro resultado para uma sequência diferente. Se não houver duplicatas para todas as permutações, o programa indica sucesso. Nove caracteres foram escolhidos como sendo o maior tamanho de caracteres prontamente computados repetidamente na minha caixa.

Alteração II Conforme indicado por um leitor estudioso, o objetivo pretendido descrito não é obtido através do código que o acompanha. O caso de teste é obviamente inadequado.

motoku
fonte
3
Parece uma boa pergunta, e fico feliz em ver que você mostrou seu processo de golfe em detalhes. Mas não sei o que você quer dizer com programa de "hash". Você deve publicar uma especificação que explique como a entrada deve ser recebida, como a saída deve ser fornecida e que relação a saída deve ter com a entrada.
Xnor
@xnor isso é suficiente?
motoku
Para o código de golfe, você definitivamente deve remover alguns desses espaços opcionais. Além disso, use o Python 2, pois a impressão é mais curta. print"x"em vez deprint("x")
mbomb007
E use uma compreensão da lista em vez de list()?
mbomb007
3
Seu processo parece bom. Comece com um programa, encurtado por tentativa / erro. Obtenha mais experiência e navegue pelas dicas de python e você estará se saindo muito bem em pouco tempo.
Geobits

Respostas:

11

Não existe uma maneira "certa" de jogar golfe. Você se saiu bem e o processo usado é bastante padrão. Transformar o programa em uma declaração geralmente não é um requisito.

Se ajudar, eis como eu abordaria o golfe no seu programa ...

Na função de hash, a instrução for pode ser substituída por uma soma:

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

Isso pode ser definido como uma função lambda:

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

E agora removemos espaços e colchetes desnecessários:

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

Como o Sp3000 apontou, isso pode ser reduzido ainda mais com enumerar:

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

Passando para a função de teste, mesclamos suas duas primeiras linhas:

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

Como ambas as funções são usadas apenas uma vez, podemos mover tudo em linha:

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

Isso é mais curto como compreensão da lista:

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

Em seguida, atribuímos um nome mais curto e removemos os espaços desnecessários novamente:

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

A instrução if pode ser movida dentro da função de impressão:

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

No entanto, geralmente é mais curto para usar e / ou:

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

Como len(x)não muda, podemos calcular e codificar seu valor:

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

Após remover espaços desnecessários e alternar a comparação, obtemos:

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

Isso nos permite mover tudo para uma declaração:

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 agora podemos usar uma compreensão de conjunto:

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

O resultado é 210 bytes, excluindo importações. O próximo passo provavelmente seria reduzir as importações ou as longas cordas.

grc
fonte
7
Curiosamente, eu acho que enumerateé mais curto:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000 26/02
@ Sp3000 oh legal! Todo builtin tem seu dia: D
grc