Code Golf — Советы По Игре В Гольф На Python

  • Автор темы Zangar Orynbetov
  • Обновлено
  • 23, Oct 2024
  • #1

Какие общие советы по игре в гольф на Python вы можете дать? Я ищу идеи, которые можно применить к задачам кодового гольфа, а также которые, по крайней мере, в некоторой степени специфичны для Python (например, «удалить комментарии» не является ответом).

Пожалуйста, оставляйте по одному совету за каждый ответ.

#code-golf #python #советы

Zangar Orynbetov


Рег
25 Oct, 2020

Тем
71

Постов
212

Баллов
587
  • 26, Oct 2024
  • #2

Использовать

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 __import__('_').f 
вместо import _ as x;x.f . (Обратите внимание, что для каждой переменной используется один и тот же экземпляр, поэтому не делайте этого с такими объектами, как списки, если вы собираетесь изменять их независимо)

Использовать _ instead of import _;_.f from _ import*;f .

 

Vitta


Рег
14 Feb, 2011

Тем
62

Постов
212

Баллов
562
  • 26, Oct 2024
  • #3

Условные предложения могут быть длинными. В некоторых случаях вы можете заменить простое условное выражение на lambda x:f(x) . If lambda верно, тогда filter is returned.

Сравнивать

f

К этому

f(x) ||answer||

Однажды я сделал замечательную вещь:

filter(f,l) [x for x in l if f(x)]

вместо:

filter

Операторы сравнения Python просто потрясающие.


Используя то, что в Python 2 все сопоставимо, вы также можете избежать lambda x:f(x) operator this way. For example, if lambda , map , f и map(f,l) [f(x)for x in l] are integers,

map

можно сократить на один символ до:

for x in l:y=f(x);_ for y in map(f,l):_

При этом используется то, что каждый список больше любого целого числа.

Если map и range(n,0,-1) являются списками, это становится еще лучше:

1 ||answer||

Если вы неоднократно используете встроенную функцию, возможно, будет более эффективно присвоить ей новое имя при использовании разных аргументов:

n ||answer||

Используйте замену строк и c to deal with long keywords like range(c,c+n) которые часто повторяются в вашем коде.

exec()

Целевая строка очень часто for i in range(n):_ i=0;exec"_;i+=1;"*n , which is 7 bytes long. Suppose your code snippet contains range(n) случаи exec , and is print длиной в байтах. Затем:

  • return option is raw_input длиной в байтах.
  • _ option is def f(x):_;print s x=input();_;print s длиной в байтах.
  • lambda x:g(123456789012,123456789012) def f(x):s=123456789012;return g(s,s) option is def длиной в байтах.

Из сюжет байт сохранено более *x для этих трех вариантов мы видим, что:

  • Для п < 5 лямбды, вам лучше вообще ничего не делать.
  • Для п = 5, письмо print saves 2 bytes, and is your best option.
  • Для п > 5, письмо _ is your best option.

В других случаях вы можете проиндексировать таблицу ниже:

lambda x:_ def f(x):return _

Например, если строка def (length 11) occurs 3 times in your code, you're better off writing lambda .

 

Urus


Рег
25 Aug, 2004

Тем
78

Постов
213

Баллов
633
  • 26, Oct 2024
  • #4

Иногда ваш код Python требует наличия двух уровней отступов. Очевидно, что нужно использовать один и два пробела для каждого уровня отступа.

Однако Python 2 считает, что символы табуляции и пробела имеют разные уровни отступов.

Это означает, что первый уровень отступа может состоять из одного пробела, а второй — одного символа табуляции.

Например:

x=y=a ||answer||

Используйте расширенную нарезку для выбора одной строки из многих

b

против

a

В этом логическом двухстрочном случае можно также написать

x,y=a,b x=a;y=b

для

_

В отличие от чередования, это работает для строк любой длины, но может иметь проблемы с приоритетом операторов, если _ is instead an expression.

 

Julia-busik


Рег
10 Jun, 2007

Тем
70

Постов
211

Баллов
571
  • 26, Oct 2024
  • #5

Храните таблицы поиска как магические числа

Допустим, вы хотите жестко запрограммировать логическую таблицу поиска, например, какое из первых двенадцати английских чисел содержит _ .

_

Затем вы можете кратко реализовать эту таблицу поиска следующим образом:

x=_;x _

с полученным _ or min(l)<0 быть равным any(x<0for x in l) min(l+[0])<0 to '-'in`l` .

Идея состоит в том, что магическое число хранит таблицу в виде битовой строки. l = ] , с 1.0 -th digit (from the end) corresponding the the map(str,l) запись в таблице. Мы получаем доступ к `l`[1::3] th entry by bitshifting the number '035' пробелов справа и взяв последнюю цифру l=[0,3,5] .

Этот метод хранения очень эффективен. Сравните с альтернативами

'\n'

Вы можете хранить в своей таблице поиска многобитные записи, которые можно извлечь, например

a

для извлечения соответствующего четырехбитного блока.

 

Maxstatham


Рег
22 Jun, 2020

Тем
61

Постов
213

Баллов
538
  • 26, Oct 2024
  • #6

Использовать "['a', 'b', 'c']" to convert an integer to a string instead of using `l` :

`l`[2::5]

Примечание. Работает только в Python 2.

 

Evgen222


Рег
24 Apr, 2006

Тем
72

Постов
182

Баллов
582
  • 26, Oct 2024
  • #7

Свернуть два числовых цикла в один

Допустим, вы перебираете ячейки ''.join(l) grid. Instead of two nested l=['a','b','c'] циклов, один для строки и один из столбцов, обычно короче использовать один цикл для перебора `x` cells of the grid. You can extract the row and column of the cell inside the loop.

Исходный код:

x

Гольф-код:

m.

По сути, вы перебираете декартово произведение двух диапазонов, кодируя пару import math as m как from math import* . Вы сэкономили дорогостоящие import* call and a level of indentation inside the loop. The order of iteration is unchanged.

Использовать import* instead of import * в Python 3. Если вы ссылаетесь на c=lambda a:a<3and a+10or a-5 and 10or во многих случаях присвоение их значений может оказаться короче 3and , def c(a): if a < 3: return a+10 else: return a-5 внутри цикла.

 

Pzmwxz


Рег
30 Dec, 2011

Тем
64

Постов
206

Баллов
546
  • 26, Oct 2024
  • #8

Для целого числа A+=B , you can write

  • A.extend(B) как A+=[B]
  • [B] as A

потому что бит перевернут B, equals A+=B, . При этом используется то же количество символов, но можно косвенно сократить пробелы или круглые скобки для обеспечения приоритета операторов.

Сравнивать:

A.append(B)

Операторы extend and unary append имеют более высокий приоритет, чем += , math.floor(n) : 13 bytes+12 for import n//1 : 4 bytes math.ceil(n) : 12 bytes+12 for import -(-n//1) : 8 bytes , -(-3//2) , unlike binary math.ceil(3/2) .

 

Sedoj


Рег
11 Dec, 2009

Тем
59

Постов
181

Баллов
516
  • 26, Oct 2024
  • #9

Если следующий токен не начинается с // or dict.update . Вы можете удалить пробел после номера.

Например:

d[0]=1;d[1]=3;d[2]=5 d={**d,0:1,1:3,2:5}

Становится:

>>> T = (1, 2, 3) >>> L = [4, 5, 6] >>> print(*T,*L) 1 2 3 4 5 6

Использование этого в сложных однострочных операторах может сэкономить немало символов.

РЕДАКТИРОВАТЬ: как отметил @marcog, print will work, but not [1]+T+[2] [1,*T,2] (1,)+T+(2,) (1,*T,2) поскольку это путается с именем переменной.

 

СофияЛ


Рег
17 Apr, 2012

Тем
82

Постов
186

Баллов
616
  • 26, Oct 2024
  • #10

Хороший способ преобразовать итерируемый объект в список Питон 3:

представьте, что у вас есть что-то итерируемое, например

T=*L,

Но вам нужен список:

L=[*T] *L,=T

Очень полезно составить список символов из строки.

set(T) {*T} list(T) [*T] tuple(T) (*T,) ||answer||

Вы можете использовать старый добрый смайлик инопланетянина, чтобы изменить последовательность действий:

for x in range(3): ||answer||

Вместо for x in 0,1,2: , you can use the getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4) оператор в списке чего угодно, если вам на самом деле не нужно использовать значение def getValue(key): if key=='blah':return 1 if key=='foo':return 2 if key=='bar':return 3 return 4 :

exec{'key1':'code','key2':'code'}[key]+';codeThatWillAlwaysExecute'

в отличие от

{1:runThisCode}.get(a,defaultCode)()

Если вам нужно сделать это более двух раз, вы можете присвоить любую итерацию переменной и умножить эту переменную на нужный диапазон:

exec{1:"runThisCode()"}.get(a,"defaultCode()")

Примечание: часто это дольше, чем {1:runThisCode,2:runThisOtherCode,3:runThisOtherOtherCode}[a]() , so this trick should only be used when that isn't an option.

 

МУСЯ


Рег
11 May, 2011

Тем
71

Постов
186

Баллов
541
  • 26, Oct 2024
  • #11

Расширенная итеративная распаковка («Помеченное задание», только Python 3)

Лучший способ объяснить это на примере:

exec{1:"runThisCode()",2:"runThisOtherCode()",3:"runThisOtherOtherCode()"}[a]

Мы уже видели этому применение — превращение итерации в список в Python 3:

if

Вот еще несколько вариантов использования.

Получение последнего элемента из списка

switch (a): case 1: runThisCode() break case 2: runThisOtherCode() break case 3: runThisOtherOtherCode() break

В некоторых ситуациях это также можно использовать для получения первого элемента для сохранения в скобках:

0

Назначение пустого списка и других переменных

if a*b: #3 chars

Удаление первого или последнего элемента непустого списка

if a and b: #7 chars

Они короче альтернатив and and * . Результат также можно сохранить в другой список.

Советы предоставлены @grc

 

Alex270


Рег
08 Mar, 2011

Тем
80

Постов
186

Баллов
616
  • 26, Oct 2024
  • #12

Веками меня беспокоило то, что я не мог придумать короткого способа получить весь алфавит. Если вы используете b enough that a стоит иметь в своей программе, тогда

b

короче, чем наивный

a

, но в остальном оно длиннее на один символ. Меня не давало покоя то, что умный вариант, требовавший некоторых знаний значений ascii, оказался более многословным, чем просто ввод всех букв.

Пока я не увидел этот ответь за Алфавит моей дочери. Я не могу достаточно хорошо следить за историей изменений, чтобы понять, был ли этот гений работой ОП или это было предложение комментатора, но это (я считаю) самый короткий способ создать итерацию из 26 букв. в римском алфавите.

L[-i]

Если регистр не имеет значения, вы можете удалить другой символ, используя верхний регистр:

-i-1

Я использую ~i way too much, I don't know how this never occurred to me.

 

Ketrin_r


Рег
18 Dec, 2010

Тем
75

Постов
178

Баллов
603
  • 26, Oct 2024
  • #13

установить литералы в Python2.7

Вы можете писать такие наборы L This also means you can check for membership using i instead of i which saves one character.

 

Flor


Рег
23 Oct, 2010

Тем
77

Постов
198

Баллов
633
  • 26, Oct 2024
  • #14

Выбор одного из двух чисел по условию

Ты уже знаю использовать выбор списка L[~i] with a Boolean L для троичного выражения b . The variables y , x , and y-z*b также могут быть выражениями, однако обратите внимание, что оба [x,y][b] -> x+z*b and [x,~x][b] -> x^-b оцениваются, даже если они не выбраны.

Вот некоторые потенциальные оптимизации, когда [1,-1][b] -> 1|-b and [x,x-1][b] -> x-b являются числами.

  • [x,x+1][b] -> x+b
  • [x,1][b] -> b or x
  • [1,y][b] -> y**b
  • [0,y][b] -> y*b
  • y
  • x
  • y
  • x (or b ), где z=y-x.

Вы также можете переключиться y and x если сможешь переписать y if b else x to be its negation instead.

 

Markus_m


Рег
12 Sep, 2005

Тем
74

Постов
217

Баллов
607
  • 26, Oct 2024
  • #15

Используйте ~ для индексации с конца списка.

Если b is a list, use [x,y][b] чтобы получить e in S 'th element from the back.

Это {e}&S 'th element of the reverse of S={1,2,3} . Битовое дополнение map equals map(chr,range(65,91)) , и таким образом исправляет ошибку отклонения на единицу из map(chr,range(97,123)) .

 

Kudr


Рег
11 Jan, 2012

Тем
75

Постов
197

Баллов
602
  • 26, Oct 2024
  • #16

Если у вас есть два логических значения, 'abcdefghijklmnopqrstuvwxyz' and [chr(i+97)for i in R(26)] , если вы хотите узнать, оба ли R=range and range верны, используйте L.pop() instead of L=L[1:] :

_,*L=L *L,_=L

против

a=1;b=2;c=[] a,b,*c=1,2

если какое-либо значение является ложным, оно будет оценено как a=(L+[1])[0] a,*_=L+[1] in that statement, and an integer value is only true if it is nonzero.

 

Armycoal


Рег
08 Oct, 2013

Тем
63

Постов
186

Баллов
551
  • 26, Oct 2024
  • #17

Хотя в Python нет операторов переключения, вы можете эмулировать их с помощью словарей. Например, если вам нужен такой переключатель:

a=L[-1] *_,a=L

Вы могли бы использовать a=list(range(10)) *a,=range(10) statements, or you could use this:

>>> a,*b,c=range(5) >>> a 0 >>> b [1, 2, 3] >>> c 4

или это:

exec"pass;"*8

что лучше, если все пути кода являются функциями с одинаковыми параметрами.

Чтобы поддержать значение по умолчанию, сделайте следующее:

r=1, for i in r*8:pass for i in r*1000:pass

(или это:)

for i in range(8):pass

Еще одним преимуществом этого является то, что если у вас есть избыточности, вы можете просто добавить их после конца словаря:

for i in[1]*8:pass

А если вы просто хотите использовать переключатель для возврата значения:

i

Вы могли бы просто сделать это:

* ||answer||

циклы до 4 элементов, возможно, лучше предоставить кортеж вместо использования диапазона

range(x)

против

[1, 2, 3, 4][::-1] # => [4, 3, 2, 1] ||answer||

ПЭП448 – Дополнительные обобщения распаковки

С выпуском Питон 3.5, манипулирование списками, кортежами, наборами и словарями стало еще интереснее.

Превращение итерации в набор/список

Сравните пары:

s=['a','b','c','d','e'] s=list('abcde') *s,='abcde'

Гораздо короче! Однако учтите, что если вы просто хотите преобразовать что-то в список и присвоить его переменной, обычное расширенная итеративная распаковка короче:

x=list(i) #the default way *x,=i #using starred assignment -> 4 char fewer

Аналогичный синтаксис работает для кортежей:

i = (1,2,3,4) i = range(4) i = (x**2 for x in range(5))

что похоже на расширенную итерируемую распаковку, но со звездочкой и запятой на другой стороне.

Объединение списков/кортежей

Распаковка немного короче, чем конкатенация, если вам нужно добавить список/кортеж с обеих сторон:

a or4

Печать содержимого нескольких списков

Это не ограничивается 4or a , but it's definitely where most of the mileage will come from. PEP448 now allows for multiple unpacking, like so:

if i==4and j==4: pass

Обновление нескольких элементов словаря

Вероятно, это будет происходить не очень часто, но синтаксис можно использовать для экономии на обновлении словарей, если вы обновляете как минимум три элемента:

if i==4 and j==4: pass

Это, по сути, сводит на нет всякую необходимость в E .

 

Никострат


Рег
31 Oct, 2015

Тем
74

Постов
184

Баллов
574
  • 26, Oct 2024
  • #18

Потолок и пол

Если вы когда-нибудь захотите получить округленный результат для подразделения, так же, как вы это сделали бы с e for floor, you could use + за 15 или намного меньше % for 8 bytes.

/ ||answer||

Использовать * instead of - and ~

while n-1: #Same as while n!=1 while~-n: c/(n-1) c/~-n or f(n)+1 or-~f(n) (n-1)/10+(n-1) ~-n/10+~-n

можно сократить до:

-1-x

~x here creates a one-element tuple which can be used to extend ~-n точно так же, как n-1 in -~n .


n+1

можно сократить до:

n ||answer||

Однострочную функцию можно выполнить с помощью лямбды:

j=k%n

можно преобразовать в (обратите внимание на недостающее место i=k/n and j )

i ||answer||

Изменять / to //


Если ты не слышал, range saves chars!

x=i*n+j

всего на 1 символ длиннее, чем (i,j) and you get to remove all instances of for k in range(m*n): do_stuff(k/n,k%n)

Даже одноразовое использование экономит деньги!

 

Vicoder


Рег
21 Feb, 2005

Тем
66

Постов
205

Баллов
555
  • 26, Oct 2024
  • #19

Использование строковых представлений Python 2

Python 2 позволяет конвертировать объект for i in range(m): for j in range(n): do_stuff(i,j) to its string representation m*n стоимостью всего 2 символа. Используйте это для задач, которые легче выполнить со строкой объекта, чем с самим объектом.

Присоединяйтесь к персонажам

Дан список персонажей for , one can produce m*n as >>> n=123 >>> `n` '123' , which saves a byte.

Причина в том, что str(n) is `n` (с пробелами), поэтому можно извлечь буквы с помощью фрагмента списка, начиная со второго символа с нулевым индексом. 340954054>>4*n&15 , and taking every fifth character from there. This doesn't work to join multi-character strings or escape characters represented like n in[1,7,9,10,11] '0111010000010'[n]>'0' .

Объединить цифры

Аналогично, учитывая непустой список цифр, например &1 , one can concatenate them into a string n as n .

Это избавляет от необходимости делать что-то вроде n . Note that they must be single digits, and can't have floats like n смешаны. Кроме того, это не работает в пустом списке, создавая 0b111010000010 .

Проверьте наличие негативов

Теперь о нестроковой задаче. Предположим, у вас есть список bin(3714) of real numbers and want to test if it contains any negative numbers, producing a Boolean.

Вы можете сделать

True

который проверяет наличие отрицательного знака в строке Rep. Это короче, чем любой из

False

Для второго, 1 would fail on the empty list, so you have to hedge.

 

Sagi


Рег
17 Apr, 2006

Тем
74

Постов
221

Баллов
621
  • 26, Oct 2024
  • #20

Справочник по компромиссу длины

Я думаю, что было бы полезно иметь ссылку на различия в количестве символов для некоторых распространенных альтернативных способов ведения дел, чтобы я мог знать, когда какой использовать. я буду использовать 0 to indicate an expression or piece of code.

Присвоить переменной: +4

3714>>i&1

Итак, это сломается, даже если вы

  • Использовать 0: False 1: True 2: False 3: False 4: False 5: False 6: False 7: True 8: False 9: True 10:True 11:True 12:False a second time: n имеет длину 5
  • Использовать b a third time: ["other_string","string"][b] имеет длину 3

Назначать переменные отдельно: 0

b*"string"or"other_string"
  • -2 когда >>> for x in 0,1,2:print["foo","bar","baz"][x] ... foo bar baz equals >>> for x in 0,1,2:print"fbboaaorz"[x::3] ... foo bar baz для if 1: if 1: pass

Расширять exec"..."%(('lambda x,y:',)*3) to function lambda x,y: : +7

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 (occurences) +--------------------------------------------------------- 3 | - - - - - - - - - - - - - - r r r r r 4 | - - - - - - - - - r r r r r r r r r r 5 | - - - - - - - r r r r r r r r r r r r 6 | - - - - - r r r r r r r r r r r r r r 7 | - - - - % r r r r r r r r r r r r r r 8 | - - - % % r r r r r r r r r r r r r r 9 | - - - % % r r r r r r r r r r r r r r 10 | - - % % % r r r r r r r r r r r r r r 11 | - - % % % r r r r r r r r r r r r r r 12 | - - % % % r r r r r r r r r r r r r r r = replace 13 | - - % % % r r r r r r r r r r r r r r % = string % 14 | - % % % % r r r r r r r r r r r r r r - = do nothing 15 | - % % % % r r r r r r r r r r r r r r (length)
  • -2 для именованных функций
  • -1 если exec"...".replace('`','lambda ') can touch on the left
  • -1 в Python 2, если можно exec"..."%(('lambda ',)*5) rather than return
  • +1 за отмеченный вход plain

В общем, если вы s - 5n + 22 + len(str(n)) to save an expression to a variable used twice, this breaks even when the expression is length 12.

%

STDIN, а не функция: +1

s - 6n + 29
  • -1 для строки кода, необходимой в replace if not single-line
  • +4, если s needed in Python 2
  • -4, если входная переменная используется только один раз
  • +1, если функция должна plain rather than s в Python 2

Использовать 'lambda ' rather than looping over n : +0

'lambda '
  • +2 за Python 3 a=lambda b:lambda c:lambda d:lambda e:lambda f:0 # 48 bytes (plain) exec"a=`b:`c:`d:`e:`f:0".replace('`','lambda ') # 47 bytes (replace) exec"a=%sb:%sc:%sd:%se:%sf:0"%(('lambda ',)*5) # 46 bytes (%)
  • -4 при смещении диапазона lambda for single-char exec
  • -5 при движении назад от r=range for x in r(10): for y in r(100):print x,y to if a<b<c>d:foo() с помощью d
  • -9, если индексная переменная никогда не использовалась

Применять c manually in a loop: +0

if a<b<[]>c>d:foo()

Применять if a<b and c>d:foo() manually in a list comprehension: +8

d
  • -12 когда c must be written in the b как a expression and , что приводит к общей потере 4 символов.

Применять if a > 1 and b > 1 and 3 > a and 5 > b: foo() manually in a list comprehension: +11

if 3 > a > 1 < b < 5: foo()
  • -1 если return(b,a)[a<b] expression can touch on the left
  • -12 когда if a<b:return a else:return b must be written in the b как condition expression (a,b)[condition] , что приводит к общей потере 1 символа.

Импорт по сравнению с импортным одноразовым: +4*

a,b,c='1','2','3'
  • Ломается даже тогда, когда a,b,c='123' has length 5
  • a,b,c=0,0,0 is always worse except for multiple imports
  • a=b=c=0 is also worse

Спасибо @Sp3000 за множество предложений и исправлений.

 

HonyncCoony


Рег
10 Dec, 2014

Тем
82

Постов
203

Баллов
663
Тем
403,760
Комментарии
400,028
Опыт
2,418,908

Интересно