您使用Python打高尔夫球有哪些一般技巧?我正在寻找可以应用于代码高尔夫球问题的想法,并且这些想法至少也特定于Python(例如,“删除注释”不是答案)。
请为每个答案发布一个提示。
您使用Python打高尔夫球有哪些一般技巧?我正在寻找可以应用于代码高尔夫球问题的想法,并且这些想法至少也特定于Python(例如,“删除注释”不是答案)。
请为每个答案发布一个提示。
Answers:
使用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]()
使自己的短路与lambda表达式
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()
可以缩短一个字符以:
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个缩进级别。显而易见的事情是为每个缩进级别使用一个和两个空格。
但是,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))
字节。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
是巨大的。
=>
仅仅是string = lambda
。例如,f=>:0
将为f = lambda: 0
。
使用扩展切片从多个字符串中选择一个字符串
>>> 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
在这种布尔型两字符串的情况下,也可以写
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`
整数转换为字符串,而不是使用str(n)
:
>>> n=123
>>> `n`
'123'
假设您要对布尔值查找表进行硬编码,例如前十二个英文数字中的哪个包含一个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
提取相关的四位块。
假设您要遍历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
在循环中节省了昂贵的调用和一定程度的缩进。迭代顺序不变。
使用//
而不是/
如果你是指在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
在复杂的单行语句中使用此功能可以节省很多字符。
编辑:正如@marcog指出的那样,4or a
可以使用,但是不能a or4
与变量名混淆。
if(i,j)==(4,4):
甚至更短,在这种特殊情况下if i==j==4:
4or a
作品,但没有a or4
0or
也不起作用(0o
是八进制数字的前缀)。
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-x)
。
a+b+1
可以更简洁地编写为a-~b
。
n-i-1
就是n+~i
。
在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]
您可以使用外星人的老笑脸来反转序列:
[1, 2, 3, 4][::-1] # => [4, 3, 2, 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
在某些情况下,这也可以用于获取要保存在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=[]
很多次。您可以将char保存在如此简单的内容上,这真是令人惊讶。
a,*L=1,
),但它仍然节省了一个字符:)
a,*_,b=L
很久以来,我一直不敢想出一个简短的方法来获取整个字母。如果您在程序中使用range
了R=range
值得拥有的东西,那么
[chr(i+97)for i in R(26)]
比天真短
'abcdefghijklmnopqrstuvwxyz'
,但更长的时间是单个字符。令我困扰的是,一个聪明的人需要一定的ascii值知识,最终变得比仅仅键入所有字母更加冗长。
直到我看到这个答案对我女儿的字母。我无法很好地了解编辑历史记录,无法弄清楚这个天才是OP的工作,还是评论员的建议,但这(我认为)是创建26个字母中的可迭代字母的最短方法在罗马字母中。
map(chr,range(97,123))
如果大小写无关紧要,则可以使用大写字母剥离另一个字符:
map(chr,range(65,91))
我使用map
太多了,我不知道这是怎么发生的。
string.lowercase
-就是这样做的。
ord('z')
)?除了长度相同外...如果您需要字母数字,请str.isalpha
在@quintopia的版本中替换为str.isalnum
。(但是,如果只需要一种情况,则整个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)()
这样做的另一个优点是,如果确实有冗余,则可以在字典末尾添加它们:
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
与
if a*b: #3 chars
如果两个值中的任何一个为false,则它将按0
该语句计算,并且整数值只有在非零时才为true。
&
:a=b=False
,a&b
+
的or
,如果你能保证a != -b
|
在所有情况下均有效。
*
而不是and
/ &&
以多种语言保存一些字节。
Python 2使您仅需2个字符x
即可将对象转换为其字符串表示形式`x`
。使用此选项可完成比对象本身更容易在对象字符串上完成的任务。
加入角色
给定一个字符列表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
是生成器语句,而不是列表)只为我节省了一个字节……还是值得的!
一行函数可以使用lambda来完成:
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
条件为真)时才执行随后的所有操作。因此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而不是ceil,但这确实意味着ceil(n)= n + 1,但它应该适用于所有非整数值
round(x)
是(x+.5)//1
+1字节,但后者以开头(
,如果x
是一个由常数组成的和,则可能很有用。
+=
代替append
和extend
A.append(B)
可以缩短为:
A+=B,
B,
在这里创建一个元素元组,可以A
像[B]
in中一样用于扩展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()