Чи правильно я гольф-код?


12

Мені цікаво, якщо я правильно гольф-коду. Я ставлю перед собою завдання зробити невелику програму хешування в одну заяву в Python. Я вперше почав із:

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

Потім я зробив функцію рекурсивною:

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

Я спробував укоротити його лямбдаю для повторення коду (він не працював):

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)

Нарешті я закінчився лямбда:

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

Я хотів, щоб програма була однією заявою, тому спочатку я придумав:

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

І нарешті я закінчив:

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

Це так, як розробляються проблеми кодогольфа? Я ніколи не робив подібних справ, тому зараз просто хочу знати, чи правильно я це роблю.

Поправка: Ця програма робить всю роботу для вас; тому я тут буду посилатися на функцію: Що стосується введення, програма приймає всі перестановки даного рядка; тут рядок - дев'ять символів, вибраних випадковим чином ascii_lowercase. Вихід - це прочитаний людиною рядок, який визначає, чи є результат кожної перестановки даної рядки дублікатом іншого результату для іншого рядка. Якщо немає дублікатів для всіх перестановок, програма вказує на успіх. Дев'ять символів було обрано як найбільшу довжину символів, які легко обчислюються неодноразово на моїй коробці.

Поправка II Як вказував старанний читач, описане призначення не отримується за допомогою супровідного коду. Тестовий випадок, очевидно, недостатній.


3
Це виглядає як гарний підказок, і мені приємно бачити, що ви детально показали свій процес гольфу. Але я не знаю, що ви маєте на увазі під програмою "хешування". Ви повинні опублікувати специфікацію, яка пояснює, як слід вводити вхід, яким чином повинен бути отриманий вихід та яке відношення має мати вихід.
xnor

@xnor цього достатньо?
мотоку

Для кодового гольфу слід обов'язково видалити ще декілька з цих необов’язкових пробілів. Також замість цього використовуйте Python 2, оскільки друк коротший. print"x"замістьprint("x")
mbomb007

І використовувати розуміння списку замість list()?
mbomb007

3
Ваш процес здається прекрасним. Почніть з програми, скорочуйте її пробою / помилкою. Отримайте більше досвіду та перегляньте поради пітона, і ви будете чудово справлятися за короткий час.
Геобіт

Відповіді:


11

Не існує «правильного» шляху до гольфу. Ви зробили добре, і процес, який ви використовували, є досить стандартним. Звичайно, перетворення програми в одну заяву зазвичай не є вимогою.

Якщо це допоможе, ось як я підійшов би до гольфу за вашою програмою ...

У функції хешування оператор for може бути замінений на суму:

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

Потім це можна визначити як лямбда-функцію:

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

А тепер видаляємо зайві пробіли та дужки:

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

Як вказував Sp3000, це можна додатково скоротити за допомогою перерахування:

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

Переходимо до тестової функції, ми об’єднуємо її перші два рядки:

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

Оскільки обидві функції використовуються лише один раз, ми можемо перемістити все в рядку:

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

Це коротше, як розуміння списку:

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

Далі ми даємо їй коротше ім’я та знову видаляємо зайві пробіли:

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

Оператор if можна перемістити всередині функції друку:

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

Однак використання та / або: зазвичай коротше:

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

Оскільки len(x)це не змінюється, ми можемо обчислити та твердо кодувати його значення:

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

Після видалення зайвих пробілів і переключення порівняння ми отримуємо:

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

Це дозволяє нам перемістити все в одне твердження:

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

А тепер ми можемо використовувати набір розуміння натомість:

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

Результат - 210 байт, без урахування імпорту. Наступним кроком, ймовірно, буде збільшити імпорт або довгі нитки.


7
Як не дивно, я думаю enumerate, що коротше:h=lambda s:sum(ord(x)<<i*len(s)for i,x in enumerate(s))
Sp3000

@ Sp3000 о приємно! У кожного вбудованого є свій день: D
grc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.