Pythonでゴルフをするための一般的なヒントは何ですか?私は、コードゴルフの問題に適用でき、Pythonに少なくともある程度固有のアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。
回答ごとに1つのヒントを投稿してください。
Pythonでゴルフをするための一般的なヒントは何ですか?私は、コードゴルフの問題に適用でき、Pythonに少なくともある程度固有のアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。
回答ごとに1つのヒントを投稿してください。
回答:
のa=b=c=0
代わりに使用しますa,b,c=0,0,0
。
のa,b,c='123'
代わりに使用しますa,b,c='1','2','3'
。
条件は長くなる場合があります。場合によっては、単純な条件をで置き換えることができます(a,b)[condition]
。場合はcondition
trueで、それから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()
Pythonの比較演算子は揺れ動きます。
Python 2ではすべてが同等であるため、and
この方法で演算子を回避することもできます。例えば、もしa
、b
、c
およびd
整数であり、
if a<b and c>d:foo()
次のように1文字短縮できます。
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
Pythonコードでは、2レベルのインデントが必要な場合があります。明らかなことは、各インデントレベルに1つと2つのスペースを使用することです。
ただし、Python 2はタブ文字とスペース文字を異なるインデントレベルと見なします。
つまり、最初のインデントレベルは1つのスペース、2番目のインデントレベルは1つのタブ文字にすることができます。
例えば:
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))
バイト長。これら3つのオプションで保存されたバイトのプロット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
は莫大です。
=>
is the string = lambda
です。たとえば、にf=>:0
なりますf = lambda: 0
。
拡張スライスを使用して、多数の文字列から1つの文字列を選択します
>>> for x in 0,1,2:print"fbboaaorz"[x::3]
...
foo
bar
baz
対
>>> 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
導き出されるかということです。
最初の12個の英語の数字のどれにが含まれているかのように、ブールルックアップテーブルをハードコーディングするとします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
番目のテーブルエントリを。n
番号n
スペースを右にビットシフトして最後の数字を取ることでthエントリーにアクセスします&1
。
この保管方法は非常に効率的です。代替案と比較してください
n in[1,7,9,10,11]
'0111010000010'[n]>'0'
ルックアップテーブルに、次のように抽出できるマルチビットエントリを保存できます。
340954054>>4*n&15
関連する4ビットブロックを抽出します。
m*n
グリッドのセルを繰り返し処理しているとします。for
行用と列用の2つのネストされたループの代わりに、通常、1つのループを使用し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)
実際には、2つの範囲のデカルト積を反復処理し、ペアを(i,j)
としてエンコードしx=i*n+j
ます。コストのかかるrange
呼び出しとループ内のインデントのレベルを節約しました。繰り返しの順序は変わりません。
使用//
するのではなく、/
あなたが参照している場合はPython 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
複雑な1行のステートメントでこれを使用すると、かなりの文字を節約できます。
編集:@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
セグメンテーション違反でインタラクティブなpython3をクラッシュします:(
[*'abcde']
。
の代わりにrange(x)
、*
実際に値を使用する必要がない場合は、任意のリストで演算子を使用できますi
。
for i in[1]*8:pass
とは対照的に
for i in range(8):pass
これを2回以上行う必要がある場合は、変数に反復可能変数を割り当て、その変数に必要な範囲を掛けることができます。
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
数値を反復処理できません。私はあなたが意味を推測r=[1]
これを説明する最良の方法は、例を介してです。
>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4
Python 3でイテレート可能オブジェクトをリストに変換することはすでに使用されています。
a=list(range(10))
*a,=range(10)
さらにいくつかの用途があります。
a=L[-1]
*_,a=L
状況によっては、これを使用して最初の要素を取得して括弧を保存することもできます。
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,
)、1文字を節約できます:)
a,*_,b=L
このようなセットを書くことができS={1,2,3}
ます。これは、1文字を保存する{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'
、それ以外の場合は1文字だけ長くなります。ascii値の知識を必要とする賢い人は、すべての文字を入力するだけでなく、より冗長になってしまったことを思い出しました。
私の娘のアルファベットのこの答えを見るまで。私はこの天才がOPの作品であるか、それがコメンターによる提案であったかどうかを理解するのに十分なほど編集履歴を追跡することはできませんが、これは26文字の反復可能なものを作成する最短の方法です(私は信じています)ローマ字で。
map(chr,range(97,123))
大文字と小文字が区別されない場合は、大文字を使用して別の文字を削除できます。
map(chr,range(65,91))
私はmap
あまりにも多くの方法を使います、私はこれが私に決して起こらなかった方法を知りません。
string.lowercase
-それが目的です。
ord('z')
)ではなく256 ですか?同じ長さであることに加えて...また、英数字が必要な場合はstr.isalpha
、@ quintopiaのバージョンをに置き換えますstr.isalnum
。(しかし、あなたは1例のみが必要な場合は、全体の36文字の文字列がよりもはやありませんfilter(str.isalnum,map(chr,range(90)))
。)
R
、私のバージョンは、あなたのオリジナルのものよりも短くなって、:'%c'*26%tuple(R(97,123))
あなたが呪文場合(のみ24文字)range
-大文字のバージョン短いそれだけで限り、アルファベットのようである
pythonには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)()
これのもう1つの利点は、冗長性がある場合、辞書の最後に追加できることです。
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ならば良いです
2つのブール値があり、a
とのb
両方がtrueであるかどうかを確認する場合はa
、代わりにをb
使用します。*
and
if a and b: #7 chars
対
if a*b: #3 chars
いずれかの値が偽の場合0
、そのステートメントのように評価され、整数値はゼロ以外の場合にのみ真になります。
&
:a=b=False
、a&b
+
のためにor
あなたが保証することができればa != -b
|
すべての状況で機能します。
*
and
/の代わりに&&
、多くの言語でいくつかのバイトを節約します。
Python 2では、わずか2文字のコストでオブジェクトx
をその文字列表現に変換できます`x`
。これは、オブジェクト自体よりもオブジェクトの文字列で簡単に実行できるタスクに使用します。
キャラクターを結合する
文字のリストを指定l=['a','b','c']
する''.join(l)
と`l`[2::5]
、as を生成してバイトを節約できます。
その理由は、すなわち`l`
ある "['a', 'b', 'c']"
一つの第二のゼロインデックス付き文字ことを開始して、リストのスライスに文字を抽出することができるように、(スペースで)a
、そこからすべての5番目の文字を取ります。これは、複数文字の文字列を結合したり、のように表現されたエスケープ文字には機能しません'\n'
。
数字を連結する
同様に、のような数字の空でないリストが与えられた場合l=[0,3,5]
、それらを'035'
として文字列に連結できます`l`[1::3]
。
これにより、次のような操作を省くことができmap(str,l)
ます。それらは1桁でなければならず、1.0
混在するような浮動小数点数を持つことはできません。また、これは空のリストで失敗し、を生成し]
ます。
ネガを確認
これで、非文字列タスクの場合。l
実数のリストがあり、負数が含まれているかどうかをテストして、ブール値を生成するとします。
できるよ
'-'in`l`
これは、文字列repの負符号をチェックします。これは、
any(x<0for x in l)
min(l+[0])<0
2つ目はmin(l)<0
、空のリストで失敗するため、ヘッジする必要があります。
str(l)[2::5]
は12バイトで、19バイトです''.join(map(str,l))
。これが発生した実際の状況(l
リストではなく、ジェネレーターステートメントがあった)で1バイトだけ節約できました...まだ価値があります!
ラムダを使用して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]
。and / orトリックは、短絡動作に依存している場合に便利です
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]
に拡張するために使用できる1要素のタプルを作成し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
。
条件に基づいて2つの数値のいずれかを選択する
あなたはすでに知っているリストの選択を使用するように[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
これはおそらくそれほど頻繁には発生しませんが、少なくとも3つの項目を更新する場合は、構文を使用して辞書の更新を節約できます。
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()