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.
print"x"
zamiastprint("x")
list()
?Odpowiedzi:
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ą:
Można to następnie zdefiniować jako funkcję lambda:
A teraz usuwamy niepotrzebne spacje i nawiasy:
Jak wskazał Sp3000, można to jeszcze bardziej skrócić, wyliczając:
Przechodząc do funkcji testowej, łączymy jej pierwsze dwa wiersze:
Ponieważ obie funkcje są używane tylko raz, możemy przenieść wszystko w linii:
Jest to krótsze określenie listy:
Następnie nadajemy mu krótszą nazwę i ponownie usuwamy niepotrzebne spacje:
Instrukcja if może zostać przeniesiona do funkcji drukowania:
Jednak zwykle jest krótszy w użyciu i / lub:
Ponieważ
len(x)
się nie zmienia, możemy obliczyć i zakodować jego wartość:Po usunięciu niepotrzebnych spacji i zmianie porównania otrzymujemy:
To pozwala nam przenieść wszystko w jedno zdanie:
A teraz możemy zamiast tego użyć zestawu rozumienia:
Wynik to 210 bajtów, z wyłączeniem importu. Następnym krokiem byłoby prawdopodobnie obniżenie importu lub długich łańcuchów.
źródło
enumerate
jest krótszy:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))