您使用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第-个数字(从末尾开始)对应于第nth个表项。我们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 如 -~nn-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+1ceil而不是ceil,但这确实意味着ceil(n)= n + 1,但它应该适用于所有非整数值
round(x)是(x+.5)//1+1字节,但后者以开头(,如果x是一个由常数组成的和,则可能很有用。
+=代替append和extendA.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]使用带有布尔值的列表选择。变量,和也可以是表达式,尽管请注意,即使未选择,它们和也会被求值。by if b else xxybxy
当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()