파이썬에서 골프를 할 때 어떤 일반적인 팁이 있습니까? 코드 골프 문제에 적용 할 수 있고 적어도 파이썬에 특정한 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).
답변 당 하나의 팁을 게시하십시오.
파이썬에서 골프를 할 때 어떤 일반적인 팁이 있습니까? 코드 골프 문제에 적용 할 수 있고 적어도 파이썬에 특정한 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).
답변 당 하나의 팁을 게시하십시오.
답변:
a=b=c=0
대신에 사용하십시오 a,b,c=0,0,0
.
a,b,c='123'
대신에 사용하십시오 a,b,c='1','2','3'
.
조건부는 길 수 있습니다. 경우에 따라 간단한 조건부를로 바꿀 수 있습니다 (a,b)[condition]
. 경우 condition
사실, 다음 b
반환됩니다.
비교
if a<b:return a
else:return b
이에
return(b,a)[a<b]
a if a<b else b
하고a<b and a or b
(lambda(): b, lambda(): a)[a < b]()
람다와 함께 자신의 단락을 만들어
P and A or B
주는 A를 고려 하십시오 bool(A)=False
. 그러나 (P and [A] or [B])[0]
일을 할 것입니다. 참조 diveintopython.net/power_of_introspection/and_or.html를 참조하십시오.
내가 한 번 큰 일은 :
if 3 > a > 1 < b < 5: foo()
대신에:
if a > 1 and b > 1 and 3 > a and 5 > b: foo()
파이썬의 비교 연산자는 흔들린다.
파이썬 2에서는 모든 것을 비교할 수 있으므로 and
이런 식으로 연산자를 피할 수도 있습니다 . 예를 들어, a
, b
, c
및 d
정수는,
if a<b and c>d:foo()
한 문자 씩 단축하여 다음을 수행 할 수 있습니다.
if a<b<[]>c>d:foo()
이것은 모든리스트가 임의의 정수보다 큰 것을 사용합니다.
c
및 d
목록 인 경우 훨씬 더 좋아집니다.
if a<b<c>d:foo()
3>a>1<b<5
[$a => $b]->[$b <= $a]
:)
if(a<b)+(c>d):foo()
*
. 는 or
것+
foo()if 3>a>1<b<5
내장 함수를 반복해서 사용하는 경우 다른 인수를 사용하는 경우 새 이름을 지정하는 것이 공간 효율적일 수 있습니다.
r=range
for x in r(10):
for y in r(100):print x,y
때때로 파이썬 코드에는 2 단계의 들여 쓰기가 필요합니다. 분명한 것은 들여 쓰기 수준마다 하나와 두 개의 공백을 사용하는 것입니다.
그러나 Python 2는 탭과 공백 문자가 다른 들여 쓰기 수준으로 간주합니다.
즉, 첫 번째 들여 쓰기 수준은 공백이되고 두 번째는 탭 문자가 될 수 있습니다.
예를 들면 다음과 같습니다.
if 1:
if 1:
\tpass
\t
탭 문자는 어디에 있습니까 ?
TabError: inconsistent use of tabs and spaces in indentation.
문자열 대체를 사용하고 코드에서 자주 반복되는 exec
긴 키워드를 처리 lambda
하십시오.
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 (%)
대상 문자열은 매우 자주 'lambda '
7 바이트 길이입니다. 코드 스 니펫에 n
발생 항목이 'lambda '
있고 s
바이트 길이 가 있다고 가정하십시오 . 그때:
plain
옵션은 s
바이트.replace
옵션은 s - 6n + 29
바이트.%
옵션은 s - 5n + 22 + len(str(n))
바이트.A로부터 의 플롯 을 통해 저장된 바이트plain
이 세 가지 옵션에 대해, 우리는 볼 수 있습니다 :
exec"..."%(('lambda ',)*5)
2 바이트를 저장하고, 당신의 최선의 선택입니다.exec"...".replace('`','lambda ')
당신의 최선의 선택입니다.다른 경우에는 아래 표를 색인 할 수 있습니다.
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)
예를 들어 lambda x,y:
코드에서 문자열 (길이 11)이 3 번 발생하면을 작성하는 것이 좋습니다 exec"..."%(('lambda x,y:',)*3)
.
replace
은 엄청납니다.
=>
그냥 문자열입니다 = lambda
. 예를 들어, f=>:0
입니다 f = lambda: 0
.
확장 슬라이싱을 사용하여 여러 문자열 중에서 하나의 문자열을 선택하십시오.
>>> for x in 0,1,2:print"fbboaaorz"[x::3]
...
foo
bar
baz
vs
>>> for x in 0,1,2:print["foo","bar","baz"][x]
...
foo
bar
baz
이 부울 2 열 경우에는 다음을 쓸 수도 있습니다.
b*"string"or"other_string"
...에 대한
["other_string","string"][b]
인터리빙과 달리 길이에 관계없이 문자열에 적용되지만 b
표현식 인 경우 연산자 우선 순위 문제 가 발생할 수 있습니다 .
for x in ("foo","bar","baz"): print x
x
렌더링 되는지에 대한 예일뿐입니다 . 골프 부분은 "fbboaaorz"[x::3]
vs. 가치가 ["foo","bar","baz"][x]
어떻게 x
파생 되는지는 골프 솔루션의 또 다른 부분 일 것입니다.
부울 룩업 테이블을 하드 코딩하고 싶다고 가정 해 봅시다 n
.
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
그런 다음이 조회 테이블을 다음과 같이 간결하게 구현할 수 있습니다.
3714>>i&1
결과로 0
또는 1
이상임 False
에 True
.
매직 번호는 테이블을 비트 열 bin(3714)
= 으로 저장하고 0b111010000010
,- n
번째 숫자 (끝부터)는 n
th 테이블 항목에 해당합니다 . n
숫자 n
공간을 오른쪽 으로 비트 시프 팅 하고 마지막 자리를로 이동 하여 th 엔트리에 액세스합니다 &1
.
이 저장 방법은 매우 효율적입니다. 대안과 비교
n in[1,7,9,10,11]
'0111010000010'[n]>'0'
룩업 테이블에 다음과 같이 추출 할 수있는 멀티 비트 항목을 저장할 수 있습니다.
340954054>>4*n&15
관련 4 비트 블록을 추출합니다.
m*n
격자 의 셀을 반복한다고 가정 해보십시오 . for
행과 열 중 하나에 대해 두 개의 중첩 루프 대신 단일 루프를 사용 m*n
하여 그리드 셀 을 반복하는 것이 일반적으로 더 짧습니다 . 루프 내에서 셀의 행과 열을 추출 할 수 있습니다.
원본 코드 :
for i in range(m):
for j in range(n):
do_stuff(i,j)
골프 코드 :
for k in range(m*n):
do_stuff(k/n,k%n)
실제로 두 범위의 카티 전 곱을 반복하여 쌍을 (i,j)
로 인코딩합니다 x=i*n+j
. range
루프 내에서 비용이 많이 드는 호출과 들여 쓰기 수준을 저장했습니다 . 반복 순서는 변경되지 않습니다.
사용 //
대신에 /
당신을 참조하면 파이썬 3에서 i
와 j
많은 시간, 그들의 값을 할당하는 것이 속도가 더 빠를 수 있습니다 i=k/n
, j=k%n
루프 내부.
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
루프 : repl.it/EHwa
itertools.product
특히 직교 곱을 생성 할 때 중첩 루프보다 훨씬 간결 할 수 있습니다. a1, a2, b1, b2
의 직교 제품의 예 'ab'
와'12'
다음 토큰이 e
또는로 시작하지 않는 한 E
. 숫자 다음에 오는 공백을 제거 할 수 있습니다.
예를 들어 :
if i==4 and j==4:
pass
된다 :
if i==4and j==4:
pass
복잡한 한 줄 문장에서 이것을 사용하면 문자를 상당히 줄일 수 있습니다.
편집 : @marcog가 지적했듯이 4or a
작동하지만 a or4
변수 이름과 혼동 되지 는 않습니다 .
if(i,j)==(4,4):
더 if i==j==4:
4or a
작품, 그러나a or4
0or
또한 작동하지 않습니다 ( 0o
8 진수의 접두사입니다).
0 or x
것은 아닙니다 x
. 왜냐하면 항상 돌아올 것이기 때문 입니다 . 뿐만 아니라 잘라낼 수 있습니다 0 or
.
0or
더 긴 숫자의 일부로 괜찮습니다. 10 or x
와 같습니다 10or x
.
integer의 n
경우 다음을 작성할 수 있습니다.
n+1
같이 -~n
n-1
같이 ~-n
비트 플립 ~x
이 같기 때문 -1-x
입니다. 이것은 동일한 수의 문자를 사용하지만 연산자 우선 순위를 위해 공백을 간접적으로 잘라낼 수 있습니다.
비교:
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)%10
~-n/10+~-n%10
연산자 ~
와 단항는 -
보다 높은 우선 순위이다 *
, /
, %
진 달리, +
.
-~-x
은 1 바이트를 절약 (1-x)
합니다.
a+b+1
로보다 간결하게 작성할 수 있습니다 a-~b
.
n-i-1
그냥 n+~i
입니다.
iterable을 Python 3 에 나열하도록 변환하는 좋은 방법 :
반복 가능한 것을 상상해보십시오.
i = (1,2,3,4)
i = range(4)
i = (x**2 for x in range(5))
그러나 당신은 목록이 필요합니다 :
x=list(i) #the default way
*x,=i #using starred assignment -> 4 char fewer
문자열에서 문자 목록을 만드는 것이 매우 유용합니다.
s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
*s,='abcde'
한 다음 s
segfault로 대화 형 python3 을 충돌
[*'abcde']
.
대신 실제로 다음 값을 사용할 필요가없는 경우 연산자를 목록에서 range(x)
사용할 수 있습니다 .*
i
for i in[1]*8:pass
반대로
for i in range(8):pass
이 작업을 두 번 이상 수행해야하는 경우 반복 가능 변수를 변수에 할당하고 해당 변수에 원하는 범위를 곱할 수 있습니다.
r=1,
for i in r*8:pass
for i in r*1000:pass
참고 : 이것은 종종보다 깁니다 exec"pass;"*8
. 따라서이 옵션은 옵션이 아닌 경우에만 사용해야합니다.
[1]*8
보다 짧은 문자 절약 보다 더 range(8)
적기 때문에 for i in[...
합법적 for i in range...
이지 않기 때문에 공간을 절약 할 수 있다는 것 "이라고 생각했습니다.
exec"pass;"*8
상당히 짧습니다.
r=1
, r*8
8, 당신은 숫자를 반복 할 수 없다. 나는 당신이 의미하는 것 같아r=[1]
이를 설명하는 가장 좋은 방법은 예제를 사용하는 것입니다.
>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4
우리는 이미 이것을 사용 하여 파이썬 3에서 iterable을 목록으로 바 꾸었습니다 .
a=list(range(10))
*a,=range(10)
몇 가지 용도가 더 있습니다.
a=L[-1]
*_,a=L
일부 상황에서, 이것은 첫 번째 요소를 parens에 저장하는 데 사용될 수도 있습니다.
a=(L+[1])[0]
a,*_=L+[1]
a=1;b=2;c=[]
a,b,*c=1,2
_,*L=L
*L,_=L
이러한 대안보다 짧은 L=L[1:]
하고 L.pop()
. 결과를 다른 목록에 저장할 수도 있습니다.
@grc의 팁 제공
a=1;L=[]
여러 번 썼다 . 이렇게 간단하게 문자를 저장할 수 있다는 것은 놀라운 일입니다.
a,*L=1,
). 그러나 여전히 하나의 문자를 저장합니다 :)
a,*_,b=L
이와 같이 세트를 작성할 수 있습니다. S={1,2,3}
이는 또한 하나의 문자를 저장 하는 {e}&S
대신 멤버쉽을 확인할 수 있음을 의미합니다 e in S
.
if
공백이 없기 때문에 캐릭터를 s에 저장합니다 ( if{e}&S:
)
not in
에 의해 {e}-S
그 트릭
여러 해 동안 나는 알파벳 전체를 얻을 수있는 짧은 방법을 생각할 수 없다는 것을 귀찮게했습니다. 프로그램에 range
충분한 R=range
가치가 있다면
[chr(i+97)for i in R(26)]
순진한 것보다 짧다
'abcdefghijklmnopqrstuvwxyz'
하지만 그렇지 않으면 단일 문자로 길어집니다. ASCII 값에 대한 약간의 지식이 필요한 영리한 사람은 모든 문자를 입력하는 것보다 더 장황하다는 결론을 얻었습니다.
내 딸의 알파벳에 대한 이 답변을 볼 때까지 . 이 천재가 OP의 작품인지 또는 주석 작성자의 제안인지 알아낼 수있을 정도로 편집 기록을 잘 따를 수는 없지만 26 글자의 iterable을 만드는 가장 짧은 방법입니다 (믿습니다) 로마 알파벳으로.
map(chr,range(97,123))
대소 문자가 중요하지 않은 경우 대문자를 사용하여 다른 문자를 제거 할 수 있습니다.
map(chr,range(65,91))
나는 map
너무 많이 사용, 이것이 나에게 어떻게 발생했는지 모르겠어요.
string.lowercase
.
ord('z')
) 대신 256 입니까? 영숫자가 필요한 경우 str.isalpha
@quintopia의 버전을로 바꾸십시오 str.isalnum
. (당신은 단지 하나의 사건을 필요로하지만, 전체 36 문자열보다 더 이상 없습니다 filter(str.isalnum,map(chr,range(90)))
.)
R
, 내 버전은 원래 버전보다 짧습니다 : '%c'*26%tuple(R(97,123))
(24 자 만) 철자 range
가 알파벳의 길이만큼 길다면 – 대문자 버전이 짧습니다
파이썬에는 switch 문이 없지만 사전으로 에뮬레이션 할 수 있습니다. 예를 들어 다음과 같은 스위치를 원하는 경우 :
switch (a):
case 1:
runThisCode()
break
case 2:
runThisOtherCode()
break
case 3:
runThisOtherOtherCode()
break
if
명령문을 사용 하거나 다음을 사용할 수 있습니다.
exec{1:"runThisCode()",2:"runThisOtherCode()",3:"runThisOtherOtherCode()"}[a]
아니면 이거:
{1:runThisCode,2:runThisOtherCode,3:runThisOtherOtherCode}[a]()
모든 코드 경로가 동일한 매개 변수를 가진 함수이면 더 좋습니다.
기본값을 지원하려면 다음을 수행하십시오.
exec{1:"runThisCode()"}.get(a,"defaultCode()")
(아니면 이거:)
{1:runThisCode}.get(a,defaultCode)()
이것의 또 다른 장점은 중복성이있는 경우 사전이 끝난 후에 추가 할 수 있다는 것입니다.
exec{'key1':'code','key2':'code'}[key]+';codeThatWillAlwaysExecute'
스위치를 사용하여 값을 반환하려는 경우 :
def getValue(key):
if key=='blah':return 1
if key=='foo':return 2
if key=='bar':return 3
return 4
당신은 이것을 할 수 있습니다 :
getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)
dict(s1=v1,s2=v2,...,sn=vn)
대신 {'s1':v1,'s2':v2,...,'sn':vn}
2 * n-4 바이트 를 저장하고 n> = 3 인 경우 더 좋습니다.
두 개의 부울 값이, 때 a
와 b
당신이 모두 있는지 확인하려는 경우 a
및 b
해당 사용하는 *
대신 and
:
if a and b: #7 chars
vs
if a*b: #3 chars
둘 중 하나의 값이 false이면 0
해당 명령문에서와 같이 평가되며 정수 값은 0이 아닌 경우에만 true입니다.
&
: a=b=False
,a&b
+
을 위해 or
당신이 보증되는 경우에a != -b
|
모든 상황에서 작동합니다.
*
and
/ 대신 &&
에 많은 언어로 일부 바이트를 저장합니다.
Python 2를 사용하면 단 2 개의 문자만으로도 객체 x
를 문자열 표현으로 변환 할 수 있습니다 `x`
. 객체 자체보다 객체의 문자열에서 더 쉬운 작업에 사용하십시오.
캐릭터 가입
문자 목록이 주어지면 as l=['a','b','c']
를 생성 하여 바이트를 절약 할 수 있습니다 .''.join(l)
`l`[2::5]
그 이유는이 `l`
인 "['a', 'b', 'c']"
하나가 제 제로 인덱스 문자 것으로부터리스트 슬라이스 문자를 추출 할 수 있도록, (공백) a
, 그리고 거기서부터 제 모든 문자 복용. 다중 문자 문자열을 조인하거나처럼 표현 된 이스케이프 문자는 작동하지 않습니다 '\n'
.
숫자 연결
마찬가지로, 같은 숫자의 비어 있지 않은 목록 주어진 l=[0,3,5]
하나의 문자열로를 연결할 수 있습니다, '035'
등을 `l`[1::3]
.
이렇게하면 다음과 같은 작업이 절약 map(str,l)
됩니다. 그것들은 한 자릿수 여야하고 1.0
믹싱 된 것처럼 부동 소수점을 가질 수 없습니다 . 또한 이것은 빈 목록에서 실패하여을 생성 ]
합니다.
네거티브 확인
이제 문자열이 아닌 작업입니다. l
실수 목록이 있고 음수가 포함되어 있는지 테스트하여 부울을 생성 한다고 가정하십시오 .
넌 할 수있어
'-'in`l`
문자열 rep에서 음수 부호를 확인합니다. 이 중 하나보다 짧은
any(x<0for x in l)
min(l+[0])<0
두 번째로 min(l)<0
빈 목록에서 실패하므로 헤지해야합니다.
str(l)[2::5]
는 있지만 12 바이트는 19 바이트입니다 ''.join(map(str,l))
. 이것이 발생한 실제 상황 ( l
목록이 아닌 생성기 명령문 이있었습니다 )은 1 바이트 만 절약했습니다 ... 여전히 가치가 있습니다!
람다로 한 줄 기능을 수행 할 수 있습니다.
def c(a):
if a < 3: return a+10
else: return a-5
(주없는 공간으로 변환 할 수 있습니다 3and
와 10or
)
c=lambda a:a<3and a+10or a-5
c=lambda a:a+[-5,10][a<3]
. 및 / 또는 트릭은 단락 동작에 의존 할 때 더 유용합니다
else:
삭제할 수 있으므로 return
다음에 오는 모든 것은 if
조건이 실패한 경우에만 실행되고 else
조건이 true 인 경우 일명 실행됩니다 . 따라서 else
안전하게 생략 할 수 있습니다. (외부 신 생물에 대한 자세한 설명)
c=lambda a:a-5+15*(a<3)
//
바닥에 대한 것과 마찬가지로 나누기에 대한 반올림 결과를 얻으려면 math.ceil(3/2)
15 -(-3//2)
바이트 또는 8 바이트에 대해 훨씬 더 짧게 사용할 수 있습니다 .
math.floor(n) : 13 bytes+12 for import
n//1 : 4 bytes
math.ceil(n) : 12 bytes+12 for import
-(-n//1) : 8 bytes
n//1+1
대신에 천장을 만들다의하지만 CEIL (N)을 의미 하는가 = N + 1이지만이 아닌 모든 정수 값에 대해 작동합니다
round(x)
는 (x+.5)//1
+1 바이트이지만 후자는로 시작 하며 상수로 구성된 합 (
이면 x
유용 할 수 있습니다.
+=
대신 append
하고extend
A.append(B)
단축 할 수 있습니다 :
A+=B,
B,
여기서 확장하는데 사용될 수있는 하나의 요소 터플 생성 A
마찬가지로 [B]
하여 A+=[B]
.
A.extend(B)
단축 할 수 있습니다 :
A+=B
return 0
또는 return 1
동일하다 return False
나 return True
.
-x
오히려 x*-1
. --8.32
오히려 -8.32*-1
. 아니면 그냥 8.32
...
A+=B
B
은입니다 tuple
.
조건에 따라 두 숫자 중 하나를 선택
당신은 이미 알고 목록 선택을 사용하는 [x,y][b]
부울와 b
삼항 표현 y if b else x
. 변수는 x
, y
및 b
도 표현 될하지만 모두주의 수 x
및 y
도 평가 선택하지 않은 경우.
다음은 몇 가지 잠재적 인 최적화의 x
및 y
숫자입니다.
[0,y][b] -> y*b
[1,y][b] -> y**b
[x,1][b] -> b or x
[x,x+1][b] -> x+b
[x,x-1][b] -> x-b
[1,-1][b] -> 1|-b
[x,~x][b] -> x^-b
[x,y][b] -> x+z*b
(나 y-z*b
), 여기서, Z = YX.또한 전환 할 수 있습니다 x
및 y
다시 쓸 수 있다면 b
대신 부정 될 수 있습니다.
Python 3.5 가 출시되면서 목록, 튜플, 세트 및 딕트의 조작이 골퍼가되었습니다.
쌍을 비교하십시오 :
set(T)
{*T}
list(T)
[*T]
tuple(T)
(*T,)
훨씬 짧습니다! 그러나 무언가를 목록으로 변환하고 변수에 할당하려면 일반적인 확장 가능한 반복 가능한 언 패킹 이 더 짧습니다.
L=[*T]
*L,=T
유사한 구문이 튜플에 적용됩니다.
T=*L,
확장 가능한 반복적 언 패킹과 비슷하지만 다른쪽에는 별표와 쉼표가 있습니다.
목록 / 튜플을 양쪽에 추가해야하는 경우 포장 풀기가 연결보다 약간 짧습니다.
[1]+T+[2]
[1,*T,2]
(1,)+T+(2,)
(1,*T,2)
이것은로 제한되지 않지만 print
대부분의 마일리지가 나오는 곳입니다. PEP448은 이제 다음과 같이 다중 포장 풀기를 허용합니다.
>>> T = (1, 2, 3)
>>> L = [4, 5, 6]
>>> print(*T,*L)
1 2 3 4 5 6
이것은 자주 발생하지는 않지만 적어도 세 가지 항목을 업데이트하는 경우 구문을 사용하여 업데이트 사전을 저장할 수 있습니다.
d[0]=1;d[1]=3;d[2]=5
d={**d,0:1,1:3,2:5}
이것은 기본적으로 어떤 요구도 무효화합니다 dict.update
.
>>> for i in range(x):s+=input()
i의 값 이 쓸모없는 경우 :
>>> for i in[0]*x:s+=input()
또는
>>> exec's+=input();'*x
for i in[0]*x:s+=input()
다른 공간을 절약하기 위해 두 번째 예를 만들 수 있습니다 . 또한, exec와 첫 번째 인용 부호 사이의 공백을 제거하여 얻을 수 있습니다.exec's+=input();'*x
for i in[0]*x:s+=input()