Czy prawidłowo gram w golfa?

12

Jestem ciekawy, czy prawidłowo gram w golfa. Podjąłem wyzwanie, aby przekształcić mały program mieszający w jedną instrukcję w Pythonie. Zacząłem od:

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

Następnie ustawiłem funkcję rekurencyjną:

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

Próbowałem skrócić go za pomocą lambda do powtarzania kodu (nie działało):

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)

W końcu skończyło się na 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))

Chciałem, aby program był jedną instrukcją, więc najpierw wymyśliłem:

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

I w końcu skończyło się na:

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

Czy w ten sposób rozwiązywane są problemy codegolf? Tak naprawdę nigdy tego nie robiłem, więc teraz chcę tylko wiedzieć, czy robię to dobrze.

Poprawka: Ten program wykonuje całą pracę za Ciebie; odniosę się tutaj do funkcji: Jako dane wejściowe program przyjmuje wszystkie permutacje danego ciągu; tutaj ciąg składa się z dziewięciu znaków losowo wybranych ascii_lowercase. Dane wyjściowe to czytelny dla człowieka ciąg znaków, który określa, czy wynik każdej permutacji danego ciągu jest duplikatem innego wyniku dla innego ciągu. Jeśli nie ma duplikatów dla wszystkich permutacji, program wskazuje sukces. Dziewięć znaków zostało wybranych jako największa długość znaków, które można wielokrotnie obliczać na moim pudełku.

Poprawka II Jak wskazał uważny czytelnik, opisany zamierzony cel nie został osiągnięty za pomocą załączonego kodu. Przypadek testowy jest oczywiście nieodpowiedni.

motoku
źródło
3
To wygląda na dobre pytanie ze wskazówkami i cieszę się, że szczegółowo pokazałeś swój proces gry w golfa. Ale nie wiem, co masz na myśli przez program „mieszający”. Powinieneś opublikować specyfikację, która wyjaśnia, w jaki sposób należy pobierać dane wejściowe, w jaki sposób dane wyjściowe mają być podawane, i jaki stosunek dane wyjściowe muszą mieć do danych wejściowych.
xnor
@xnor czy to wystarczy?
motoku
W przypadku golfa kodowego zdecydowanie powinieneś usunąć trochę więcej tych opcjonalnych spacji. Zamiast tego użyj Python 2, ponieważ drukowanie jest krótsze. print"x"zamiastprint("x")
mbomb007
I zamiast tego użyj rozumienia listy list()?
mbomb007
3
Twój proces wydaje się w porządku. Zacznij od programu, skróć metodą prób / błędów. Zdobądź więcej doświadczenia i przeglądaj wskazówki w języku Python, a będziesz świetnie działać w mgnieniu oka.
Geobits

Odpowiedzi:

11

Nie ma „właściwej” drogi do gry w golfa. Dobrze się spisałeś, a zastosowany proces jest dość standardowy. Jednak przekształcenie programu w jedną instrukcję zwykle nie jest wymagane.

Jeśli to pomoże, oto jak podchodziłbym do gry w golfa w twoim programie ...

W funkcji mieszającej instrukcję for można zastąpić sumą:

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

Można to następnie zdefiniować jako funkcję lambda:

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

A teraz usuwamy niepotrzebne spacje i nawiasy:

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

Jak wskazał Sp3000, można to jeszcze bardziej skrócić, wyliczając:

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

Przechodząc do funkcji testowej, łączymy jej pierwsze dwa wiersze:

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

Ponieważ obie funkcje są używane tylko raz, możemy przenieść wszystko w linii:

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

Jest to krótsze określenie listy:

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

Następnie nadajemy mu krótszą nazwę i ponownie usuwamy niepotrzebne spacje:

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

Instrukcja if może zostać przeniesiona do funkcji drukowania:

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

Jednak zwykle jest krótszy w użyciu i / lub:

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

Ponieważ len(x)się nie zmienia, możemy obliczyć i zakodować jego wartość:

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

Po usunięciu niepotrzebnych spacji i zmianie porównania otrzymujemy:

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

To pozwala nam przenieść wszystko w jedno zdanie:

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

A teraz możemy zamiast tego użyć zestawu rozumienia:

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

Wynik to 210 bajtów, z wyłączeniem importu. Następnym krokiem byłoby prawdopodobnie obniżenie importu lub długich łańcuchów.

grc
źródło
7
Co ciekawe, myślę, że enumeratejest krótszy:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000
@ Sp3000 oh nice! Każde wbudowane ma swój dzień: D
grc