Я правильно играю в гольф?


12

Мне любопытно, правильно ли я занимаюсь Code Golf. Я поставил перед собой задачу сделать небольшую программу хеширования одним выражением в 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")())

Так ли решаются проблемы Codegolf? Я никогда не делал такого рода вещи, поэтому сейчас я просто хочу знать, правильно ли я это делаю.

Поправка: эта программа делает всю работу за вас; поэтому здесь я буду ссылаться на функцию: в качестве входных данных программа принимает все перестановки данной строки; здесь строка состоит из девяти символов, выбранных случайным образом ascii_lowercase. Вывод представляет собой читаемую человеком строку, определяющую, является ли результат каждой перестановки данной строки дубликатом другого результата для другой строки. Если нет дубликатов для всех перестановок, программа указывает на успех. Девять символов было выбрано как наибольшая длина символов, легко вычисляемых многократно на моей коробке.

Поправка II Как указал старательный читатель, описанная цель не достигается с помощью прилагаемого кода. Тестовый пример явно неадекватен.


3
Это похоже на хороший вопрос, и я рад видеть, что вы подробно описали свой процесс игры в гольф. Но я не знаю, что вы подразумеваете под «хэшированием» программы. Вы должны опубликовать спецификацию, которая объясняет, как вводить данные, как выводить данные и какое отношение должны иметь выходные данные к входным данным.
xnor

@xnor этого достаточно?
Мотоку

Для кода гольф, вы должны обязательно удалить еще несколько из этих необязательных пробелов. Кроме того, используйте вместо этого Python 2, так как печать короче. print"x"вместоprint("x")
mbomb007

И использовать понимание списка вместо list()?
mbomb007

3
Ваш процесс кажется в порядке. Начните с программы, сокращенной методом проб / ошибок. Получите больше опыта и просмотрите советы по питону, и вы быстро справитесь.
Geobits

Ответы:


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:

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.