Dicas para jogar golfe em Python

248

Que dicas gerais você tem para jogar golfe no Python? Estou procurando idéias que possam ser aplicadas a problemas de código-golfe e que também sejam pelo menos um pouco específicas para Python (por exemplo, "remover comentários" não é uma resposta).

Poste uma dica por resposta.

marcog
fonte
27
Ah, eu posso ver um conjunto de perguntas como essa chegando para cada idioma ...
R. Martinho Fernandes
4
@Martinho eu concordo. Apenas iniciei um equivalente em C ++ . Porém, não acho que seja ruim, desde que não vejamos as mesmas respostas postadas em muitos desses tipos de perguntas.
marcog
50
Amo a pergunta, mas eu tenho que continuar me dizendo "Esta é apenas para se divertir e não para o código de produção"
Greg Guida
2
Esta pergunta não deveria ser uma postagem no wiki da comunidade?
Dorukayhan
3
@dorukayhan Nope; é uma pergunta válida sobre dicas de código-golfe , solicitando dicas sobre como encurtar o código python para fins de CG'ing. Tais perguntas são perfeitamente válidas para o site, e nenhuma dessas tags diz explicitamente que a pergunta deve ser feita por CW, ao contrário de SO, que exigia que os desafios de CG fossem CW. Além disso, escrever uma boa resposta e encontrar essas dicas sempre merece algo que é retirado se a pergunta for wiki da comunidade (representante).
Erik the Outgolfer 09/09/16

Respostas:

152

Use em a=b=c=0vez de a,b,c=0,0,0.

Use em a,b,c='123'vez de a,b,c='1','2','3'.

marcog
fonte
2
isso é bom ponta em geral :)
28
Observe que isso não funcionará necessariamente para definir objetos mutáveis ​​que você modificará no local. a = b = [1] é realmente diferente de um = [1]: b = [1]
isaacg
6
O engraçado da primeira dica é que ela também funciona em Java.
24714 Justin
1
@Justin Sim, mas apenas com tipos primitivos
HyperNeutrino
11
Mas NUNCA use a = b = c = [] ou qualquer instanciação de objeto, pois todas as variáveis ​​apontarão para a mesma instância. Provavelmente não é isso que você deseja.
PhE
146

Os condicionais podem ser longos. Em alguns casos, você pode substituir uma condicional simples por (a,b)[condition]. Se conditionfor verdade, bserá retornado.

Comparar

if a<b:return a
else:return b

Para isso

return(b,a)[a<b]
marcog
fonte
37
Estes não são exatamente os mesmos. O primeiro avalia apenas a expressão retornada, enquanto o segundo sempre avalia os dois. Estes fazem um curto-circuito: a if a<b else bea<b and a or b
marinus
3
(lambda(): b, lambda(): a)[a < b]()fazer o seu próprio curto-circuito com lambdas
Ming-Tang
3
@ Marinus, eles não são iguais: basta considerar P and A or Bpara qualquer A que der bool(A)=False. Mas (P and [A] or [B])[0]fará o trabalho. Consulte diveintopython.net/power_of_introspection/and_or.html para obter referência.
kgadek
6
Lambdas são muito mais longas que uma expressão condicional.
user2357112
18
@ user2357112 Mas eles fazem você parecer muito mais legal quando você os usa. :]
Chase Ries
117

Uma grande coisa que fiz uma vez é:

if 3 > a > 1 < b < 5: foo()

ao invés de:

if a > 1 and b > 1 and 3 > a and 5 > b: foo()

Os operadores de comparação do Python são ótimos.


Usando isso tudo é comparável no Python 2, você também pode evitar o andoperador dessa maneira. Por exemplo, se a, b, ce dsão inteiros,

if a<b and c>d:foo()

pode ser reduzido por um caractere para:

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

Isso usa que toda lista é maior que qualquer número inteiro.

Se ce dsão listas, isso fica ainda melhor:

if a<b<c>d:foo()
Juan
fonte
22
Claro, se isso fosse verdade golfed seria3>a>1<b<5
Rafe Kettler
4
Ame a simetria. Lembra-me do velho truque de golfe Perl para encontrar o min de $ a e $ b: [$a => $b]->[$b <= $a]:)
Simon Whitaker
Observe que o segundo exemplo (sem lista) também pode ser feito com oif(a<b)+(c>d):foo()
WorldSEnder
6
O + deve ser a *. Um orseria+
WorldSEnder
1
foo()if 3>a>1<b<5
Erik the Outgolfer
103

Se você estiver usando uma função interna repetidamente, pode ser mais eficiente em termos de espaço dar um novo nome a ela, se estiver usando argumentos diferentes:

r=range
for x in r(10):
 for y in r(100):print x,y
marcog
fonte
6
Na verdade, não salvou bytes, no entanto.
user2357112
4
r = range e os outros dois r's são 9 caracteres; usar o intervalo duas vezes tem 10 caracteres. Não é uma grande economia neste exemplo, mas basta um novo uso do alcance para obter uma economia significativa.
Frank
13
@Frank A nova linha adicional é outro personagem.
L3viathan
2
De fato, duas repetições é muito pouco para economizar em um nome de cinco funções. Você precisa: comprimento 2: 6 repetições, comprimento 3: 4 repetições, comprimento 4 ou 5: 3 repetições, comprimento> = 6: 2 repetições. AKA (comprimento-1) * (reps-1)> 4.
Ørjan Johansen
Observe que isso é aplicável a todos os idiomas com funções de primeira classe.
bfontaine 19/07
94

Às vezes, seu código Python exige que você tenha 2 níveis de indentação. O óbvio é usar um e dois espaços para cada nível de indentação.

No entanto, o Python 2 considera os caracteres de tabulação e espaço com diferentes níveis de indentação.

Isso significa que o primeiro nível de indentação pode ser um espaço e o segundo pode ser um caractere de tabulação.

Por exemplo:

if 1:
 if 1:
\tpass

Onde \testá o caractere de tabulação.

JPvdMerwe
fonte
1
Legal, eu nunca pensei sobre este!
Jules Olléon
97
Isso falha no python3: você não pode mais misturar espaços e guias (uma coisa ruim para o codegolf, mas uma coisa boa em todos os outros casos).
21413 Bakuriu
1
No python 3.4, isso parece funcionar bem.
Trichoplax
3
@trichoplax , No python 3.4.3 receboTabError: inconsistent use of tabs and spaces in indentation.
ceilingcat 3/16/16
Para referência, uma guia vale 8 espaços.
Erik the Outgolfer
87

Use a substituição de cadeias e execpara lidar com palavras-chave longas como lambdaessa, são repetidas frequentemente no seu código.

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  (%)

A cadeia de destino é muito frequentemente 'lambda ', com 7 bytes de comprimento. Suponha que seu snippet de código contenha nocorrências de 'lambda 'e tenha sbytes. Então:

  • A plainopção tem sbytes.
  • A replaceopção tem s - 6n + 29bytes.
  • A %opção tem s - 5n + 22 + len(str(n))bytes.

A partir de um gráfico de bytes salvosplain para essas três opções, podemos ver o seguinte:

  • Para n <5 lambdas, é melhor não fazer nada sofisticado.
  • Para n = 5 , a gravação exec"..."%(('lambda ',)*5)economiza 2 bytes e é sua melhor opção.
  • Para n> 5 , escrever exec"...".replace('`','lambda ')é sua melhor opção.

Para outros casos, você pode indexar a tabela abaixo:

          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)

Por exemplo, se a sequência lambda x,y:(comprimento 11) ocorrer 3 vezes no seu código, é melhor escrever exec"..."%(('lambda x,y:',)*3).

Ming-Tang
fonte
4
isso deve receber mais votos, é uma dica muito útil.
Bigblind
7
é extremamente raro que isso funcione. o custo de replaceé enorme.
Boothby
4
Quando funciona, no entanto, ajuda muito.
Undergroundmonorail
Interessante, nunca pensei nisso!
Claudiu
Eu adicionei um novo operador para lambda na minha linguagem baseada em python: =>é apenas a string = lambda . Por exemplo, f=>:0seria f = lambda: 0.
NoOneIsHere 10/03/16
78

Use fatias estendidas para selecionar uma sequência de várias

>>> 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

Nesse caso booleano de duas cordas, também é possível escrever

b*"string"or"other_string"

para

["other_string","string"][b]

Diferentemente da intercalação, isso funciona para cadeias de caracteres de qualquer tamanho, mas pode ter problemas de precedência de operador, se bfor uma expressão.

mordedor
fonte
Observe que o primeiro exemplo tem exatamente o mesmo comprimento quefor x in ("foo","bar","baz"): print x
Mateen Ulhaq 2/17/17
1
@MateenUlhaq, isso é apenas um exemplo de como os diferentes valores de xsão renderizados. A parte golfada é a "fbboaaorz"[x::3]vs. ["foo","bar","baz"][x]Como o xvalor é derivado seria outra parte da sua solução de golfe.
gnibbler
72

Use `n`para converter um número inteiro em uma string em vez de usar str(n):

>>> n=123
>>> `n`
'123'
marcog
fonte
38
Bom, mas não funciona com o Python3.
Alexandru
2
Atenção: realmente funciona para números inteiros, mas não para strings, por exemplo.
Nakilon
41
btw. `` é abreviação de repr
Alexandru
9
Inteiros menores que -2 ** 31 ou maiores que 2 ** 31-1 (Longs) recebem um 'L' no final.
hallvabo
6
Isso também pode ser usado para imprimir carros alegóricos com precisão total
gnibbler
69

Armazenar tabelas de pesquisa como números mágicos

Digamos que você deseje codificar uma tabela de pesquisa booleana, como qual dos primeiros doze números em inglês contém um 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

Em seguida, você pode implementar esta tabela de pesquisa de forma concisa como:

3714>>i&1

com o resultado 0ou 1sendo igual Falsea True.

A idéia é que o número mágico armazene a tabela como uma cadeia de bits bin(3714)= 0b111010000010, com o ndécimo-dígito (do final) correspondente à nentrada da tabela-th. Nós acessar o nth entrada por bitshifting o número nespaços para a direita e tomar o último dígito por &1.

Este método de armazenamento é muito eficiente. Compare com as alternativas

n in[1,7,9,10,11]
'0111010000010'[n]>'0'

Você pode fazer com que sua tabela de pesquisa armazene entradas multibit que podem ser extraídas como

 340954054>>4*n&15

para extrair o bloco de quatro bits relevante.

xnor
fonte
Poderíamos ter um resultado de exemplo para o bloco de quatro bits? Você usou uma regra para o bloco de n bits?
precisa saber é o seguinte
8
Às vezes, o Hex pode ser ainda menor.
Joonazan
4
Isso é útil para muitos idiomas.
Cyoce 11/02
1
@Joonazan Hex é menor para números acima de 999 999 .
Mateen Ulhaq
60

Recolher dois loops numéricos em um

Digamos que você esteja iterando sobre as células de uma m*ngrade. Em vez de dois forloops aninhados , um para a linha e uma das colunas, geralmente é mais curto usar um único loop para iterar sobre as m*ncélulas da grade. Você pode extrair a linha e a coluna da célula dentro do loop.

Código original:

for i in range(m):
 for j in range(n):
  do_stuff(i,j)

Código de golfe:

for k in range(m*n):
  do_stuff(k/n,k%n)

Na verdade, você está iterando sobre o produto cartesiano das duas faixas, codificando o par (i,j)como x=i*n+j. Você salvou uma rangechamada dispendiosa e um nível de indentação dentro do loop. A ordem da iteração é inalterada.

Use em //vez de /no Python 3. Se você se referir ie jmuitas vezes, pode ser mais rápido atribuir seus valores i=k/n, j=k%ndentro do loop.

xnor
fonte
5
Isso é incrível. Eu nunca tinha percebido que isso era possível!
Theellygusti
Vi isso nas dicas para JavaScript. É um truque bastante útil na maioria dos idiomas.
Cyoce 12/01
7
Para referência, para alargar esta a 3 ciclos:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007
3
Para nloops: repl.it/EHwa
mbomb007 27/10
Em alguns casos, itertools.productpode ser muito mais conciso do que loops aninhados, especialmente ao gerar produtos cartesianos. a1, a2, b1, b2são exemplos do produto cartesiano de 'ab'e'12'
Aaron3468
54

A menos que o token a seguir comece com eou E. Você pode remover o espaço após um número.

Por exemplo:

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

Torna-se:

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

Usar isso em instruções complicadas de uma linha pode salvar alguns caracteres.

EDIT: como @marcog apontou, 4or afuncionará, mas não a or4como isso se confunde com o nome de uma variável.

JPvdMerwe
fonte
37
if(i,j)==(4,4):é ainda mais curto e neste caso especialif i==j==4:
gnibbler
3
4or aa or4
Tags
17
0ortambém não funciona ( 0oé um prefixo para números octais).
Nabb
5
@ Nabb Não que isso importe, pois 0 or xsempre retornará x. Poderia muito bem cortar o 0 or.
precisa saber é o seguinte
5
0oré bom como parte de um número mais longo. 10 or xé equivalente a 10or x.
Trichoplax
54

Para inteiro n, você pode escrever

  • n+1 Como -~n
  • n-1 Como ~-n

porque o bit virar ~xé igual -1-x. Isso usa o mesmo número de caracteres, mas pode indiretamente cortar espaços ou aparar para precedência do operador.

Comparar:

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

Os operadores ~e unário -são mais elevados do que precedência *, /, %, ao contrário de binário +.

xnor
fonte
11
Uma variação deste truque que eu corri para hoje: -~-xsalva uma vs. byte (1-x).
Lynn
4
Outra aplicação útil é que a+b+1pode ser escrita de forma mais concisa como a-~b.
Strigoides
E n-i-1é justo n+~i.
ruohola 9/06
51

Uma boa maneira de converter uma iterável para listar no Python 3 :

imagine que você tem alguma iterável, como

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

Mas você precisa de uma lista:

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

É muito útil fazer uma lista de caracteres com uma string

s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
JBernardo
fonte
1
digitação *s,='abcde'e, em seguida, scai a minha python3 interativo com um segfault :(
daniero
@daniero Wow. Somente no console interativo? Parece muito estranho. Experimente-o em um console limpa ou reportar o bug
JBernardo
1
Meu Python 3.5 funciona bem.
NoOneIsHere 10/03/16
para i = (x ** 2 para x na faixa (5)) eu tenho esse código retornado <object gerador <genexpr> at 0x03321690>
george
7
E se você estiver fazendo isso em uma expressão, poderá fazê-lo [*'abcde'].
Esolanging Fruit
46

Em vez de range(x), você pode usar o *operador em uma lista de qualquer coisa, se realmente não precisar usar o valor de i:

for i in[1]*8:pass

em oposição a

for i in range(8):pass

Se você precisar fazer isso mais de duas vezes, poderá atribuir qualquer iterável a uma variável e multiplicá-la pelo intervalo desejado:

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

Nota : isso geralmente é mais longo que exec"pass;"*8, portanto, esse truque deve ser usado apenas quando isso não for uma opção.

Blazer
fonte
@proudhaskeller Acho que o ponto da linha que você removeu foi: "Além da economia óbvia de caracteres que você obtém porque [1]*8é menor do que range(8), você também economiza um espaço porque for i in[...é legal enquanto for i in range...não é".
Undergroundmonorail
ah, certo, eu não entendi isso. corrigido agora
proud haskeller
7
exec"pass;"*8é significativamente mais curto.
DJMcMayhem
1
se r=1, r*8for 8, e você não poderá iterar através de um número. Eu acho que você quis dizerr=[1]
Artemis Fowl
1
@ArtemisFowl, não, tudo bem, a vírgula após o 1 cria uma tupla que é iterável.
sasha
43

Você pode usar o bom e velho smiley alienígena para reverter as seqüências:

[1, 2, 3, 4][::-1] # => [4, 3, 2, 1]
Strigoides
fonte
38

Descompactação iterável estendida ("Atribuição com estrela", somente Python 3)

A melhor maneira de explicar isso é através de um exemplo:

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

Já vimos um uso disso - transformar um iterável em uma lista no Python 3 :

a=list(range(10))
*a,=range(10)

Aqui estão mais alguns usos.

Obtendo o último elemento de uma lista

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

Em algumas situações, isso também pode ser usado para obter o primeiro elemento a ser salvo em parênteses:

a=(L+[1])[0]
a,*_=L+[1]

Atribuindo uma lista vazia e outras variáveis

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

Removendo o primeiro ou o último elemento de uma lista não vazia

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

Estes são mais curtos que as alternativas L=L[1:]e L.pop(). O resultado também pode ser salvo em uma lista diferente.

Dicas cortesia de @grc

Sp3000
fonte
Uau! Eu escrevi a=1;L=[]tantas vezes. É incrível que você possa salvar caracteres em algo tão simples como esse.
Xnor
@xnor Isso é graças ao grc. Com apenas um outro elemento que não é tão bom ( a,*L=1,), mas ainda conserva um caractere :)
SP3000
não se esqueça que você também pode obter tanto o primeiro e último elemento de uma lista coma,*_,b=L
Cyoce
36

definir literais em Python2.7

Você pode escrever conjuntos como este S={1,2,3}Isso também significa que você pode verificar a associação usando, em {e}&Svez de e in Ssalvar um caractere.

mordedor
fonte
4
E isso também poupa o personagem em ifs como não há espaços ( if{e}&S:)
Artyer
1
Observe que você pode substituir not inpor {e}-Sesse truque
Black Owl Kai
35

Durante anos, me incomodou o fato de eu não conseguir pensar em uma maneira curta de obter o alfabeto inteiro. Se você usar o rangesuficiente, R=rangevale a pena ter em seu programa, então

[chr(i+97)for i in R(26)]

é mais curto que o ingênuo

'abcdefghijklmnopqrstuvwxyz'

, mas, caso contrário, é mais longo com um único caractere. Me assombrava que o inteligente que exigia algum conhecimento de valores ascii acabasse sendo mais detalhado do que apenas digitar todas as letras.

Até que eu vi essa resposta para o alfabeto da minha filha . Não consigo acompanhar o histórico de edição o suficiente para descobrir se esse gênio foi obra do OP ou se foi uma sugestão de um comentarista, mas essa é (acredito) a maneira mais curta de criar um iterável das 26 letras no alfabeto romano.

map(chr,range(97,123))

Se maiúsculas e minúsculas não importarem, você pode retirar outro caractere usando maiúsculas:

map(chr,range(65,91))

Eu uso mapdemais, não sei como isso nunca me ocorreu.

undergroundmonorail
fonte
4
Pode usar isso em codificação real, eu me sinto tão estúpido quando hardcoding estas coisas: ')
ToonAlfrink
37
Na codificação real, use string.lowercase- é para isso que serve.
Kevin S
1
se você precisar dos dois casos, a maneira mais curta que conheço é filtro (str.isalpha, map (chr, range (256))). É apenas um pouco menor que s = map (chr, range (256)); s + = map (str.lower, s)
quintopia
@ Quintopia: Por que 256 em vez de 122 ( ord('z'))? Além de ter o mesmo comprimento ... Além disso, se você precisar de alfanuméricos, substitua str.isalphana versão do @ quintopia por str.isalnum. (Mas se você só precisa de um caso, a string de 36 caráter inteiro não é mais do que filter(str.isalnum,map(chr,range(90))).)
Tim Pederick
2
Se você for injusto e usar o intervalo como R, minha versão é mais curta que a original: '%c'*26%tuple(R(97,123))(apenas 24 caracteres) se você soletrar range, é apenas enquanto o alfabeto - a versão maiúscula for mais curta
JBernardo
32

Embora o python não tenha instruções de opção, você pode emulá-las com dicionários. Por exemplo, se você deseja uma opção como esta:

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

Você poderia usar ifinstruções ou poderia usar isto:

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

ou isto:

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

o que é melhor se todos os caminhos de código forem funções com os mesmos parâmetros.

Para suportar um valor padrão, faça o seguinte:

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

(ou isto:)

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

Uma outra vantagem disso é que, se você tiver redundâncias, poderá adicioná-las após o final do dicionário:

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

E se você quiser apenas usar uma opção para retornar um valor:

def getValue(key):
    if key=='blah':return 1
    if key=='foo':return 2
    if key=='bar':return 3
    return 4

Você poderia fazer isso:

getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)
Justin
fonte
2
Isso é algo que eu consideraria profundamente usar na natureza. Sinto falta das minhas declarações de switch! 1)
HalosGhost
1
Embora em vez de usar um dicionário com teclas numeradas no primeiro exemplo, você deva usar apenas uma lista
Cyoce
1
Se você tem strings como chaves, usando dict(s1=v1,s2=v2,...,sn=vn)em vez de {'s1':v1,'s2':v2,...,'sn':vn}salva 2 * N-4 bytes e é melhor se n> = 3
Coruja preta Kai
31

Quando você tem dois valores booleanos, ae b, se você quiser descobrir se tanto ae bsão verdadeiras, use *em vez de and:

if a and b: #7 chars

vs

if a*b: #3 chars

se qualquer valor for falso, ele será avaliado como 0nessa instrução e um valor inteiro só será verdadeiro se for diferente de zero.

Justin
fonte
9
Ou você poderia usar &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs
3
usar +para orse você pode garantira != -b
undergroundmonorail
2
|funciona em todas as situações.
CalculatorFeline
1
*em vez de and/ &&salva alguns bytes em vários idiomas.
Wastl
26

Explorar representações de string do Python 2

O Python 2 permite converter um objeto xem sua representação de string `x`a um custo de apenas 2 caracteres. Use isso para tarefas que são mais fáceis de executar na cadeia de caracteres do objeto do que no próprio objeto.

Juntar personagens

Dada uma lista de caracteres l=['a','b','c'], pode-se produzir ''.join(l)como `l`[2::5], o que salva um byte.

A razão é que `l`é "['a', 'b', 'c']"(com espaços), para que se possa extrair as letras com uma fatia da lista, iniciando o segundo caractere indexado a zero ae pegando cada quinto caractere a partir daí. Isso não funciona para unir cadeias de caracteres múltiplos ou caracteres de escape representados como '\n'.

Concatenar dígitos

Da mesma forma, dada uma lista não vazia de dígitos como l=[0,3,5], pode-se concatená-los em uma string '035'como `l`[1::3].

Isso economiza fazendo algo parecido map(str,l). Observe que eles devem ter um dígito e não podem ter flutuadores 1.0misturados. Além disso, isso falha na lista vazia, produzindo ].

Verifique se há negativos

Agora, para uma tarefa não-string. Suponha que você tenha uma lista lde números reais e queira testar se ele contém números negativos, produzindo um booleano.

Você pode fazer

'-'in`l`

que verifica se há um sinal negativo na sequência rep. Este menor que qualquer um

any(x<0for x in l)
min(l+[0])<0   

Para o segundo, min(l)<0falharia na lista vazia, então você precisa fazer hedge.

xnor
fonte
Concatenar o fatiamento de seqüência de caracteres de um dígito também é eficaz no Python 3, embora menos: str(l)[2::5]seja 12 bytes, contra 19 para ''.join(map(str,l)). Uma situação real em que isso surgiu (onde lestava uma declaração de gerador, não uma lista) me salvou apenas um byte ... o que ainda vale a pena!
precisa saber é o seguinte
25

Uma função de uma linha pode ser executada com o lambda:

def c(a):
  if a < 3: return a+10
  else: return a-5

pode ser convertido em (observe falta de espaço 3ande 10or)

c=lambda a:a<3and a+10or a-5
Alexandru
fonte
21
ou c=lambda a:a+[-5,10][a<3]. o e / ou truque é mais útil quando você está dependendo do comportamento de curto-circuito
gnibbler
3
Em sua função, else: pode ser descartado como returninterrompe a execução da função; portanto, tudo o que se segue é executado apenas se a ifcondição falhar, ou seja, se a elsecondição for verdadeira. Assim, elsepode ser omitido com segurança. (Explicado em detalhes para os neófitos lá fora)
JeromeJ
c (-10) retorna -15 enquanto deve retornar 0
Anvit
ouc=lambda a:a-5+15*(a<3)
JayXon
25

loops de até 4 itens podem ser melhores para fornecer uma tupla em vez de usar o range

for x in 0,1,2:

vs

for x in range(3):
mordedor
fonte
24

Teto e Piso

Se você quiser obter o resultado arredondado de uma divisão, da mesma forma que faria com o //piso, use math.ceil(3/2)15 ou mais curto -(-3//2)para 8 bytes.

math.floor(n)   : 13 bytes+12 for import
n//1            : 4  bytes

math.ceil(n)    : 12 bytes+12 for import
-(-n//1)        : 8  bytes
Juan Cortés
fonte
5
Isso me salvou perto de 20 bytes, obrigado!
Morgan Thrapp
1
às vezes você pode começar afastado com n//1+1em vez de ceil mas faz ceil (n) média = n + 1, mas ele deve funcionar para todos os valores não inteiros
fejfo
round(x)é (x+.5)//1, +1 byte, mas o último começa com a (, e se xé uma soma que consiste em uma constante, pode ser útil.
usar o seguinte comando
23

Use em +=vez de appendeextend

A.append(B)  

pode ser reduzido para:

A+=B,

B,aqui cria uma tupla de um elemento que pode ser usada para estender Acomo [B]em A+=[B].


A.extend(B)

pode ser reduzido para:

A+=B
Homem de codificação
fonte
5
Em muitos casos (mas não todos), return 0ou return 1é equivalente a return Falseou return True.
Undergroundmonorail
5
(1) só funciona se você já sabe que o número é negativo; nesse caso, você pode salvar mais 2 caracteres usando um sinal de menos. -xao invés de x*-1. --8.32ao invés de -8.32*-1. Ou apenas 8.32...
trichoplax
Citando o OP: poste uma dica por resposta.
nyuszika7h
Observe que em A+=B Bé a tuple.
Erik the Outgolfer
23

Escolhendo um dos dois números com base em uma condição

Você já sabe usar a seleção da lista [x,y][b]com um booleano bpara a expressão ternária y if b else x. As variáveis x, ye btambém podem ser expressões, embora note que tanto xe ysão avaliadas mesmo quando não selecionado.

Aqui estão algumas otimizações em potencial quando xe ysão números.

  • [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(ou y-z*b), onde z = yx.

Você também pode alternar xe, yse puder, reescrever bpara ser sua negação.

xnor
fonte
22

Use ~ para indexar no final de uma lista

Se Lfor uma lista, use L[~i]para obter o i'ésimo elemento da parte de trás.

Este é o idécimo elemento do reverso de L. O complemento de bit ~ié igual -i-1e, portanto, corrige o erro de um por um L[-i].

xnor
fonte
21

PEP448 - Generalizações adicionais de desempacotamento

Com o lançamento do Python 3.5 , a manipulação de listas, tuplas, conjuntos e ditados ficou ainda mais complicada.

Transformando um iterável em um conjunto / lista

Compare os pares:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Muito mais curto! Observe, no entanto, que se você deseja converter algo em uma lista e atribuí-lo a uma variável, a descompactação iterável estendida normal é mais curta:

L=[*T]
*L,=T

Uma sintaxe semelhante funciona para tuplas:

T=*L,

que é como descompactar iterável estendida, mas com o asterisco e a vírgula do outro lado.

Juntando listas / tuplas

A descompactação é um pouco menor que a concatenação se você precisar anexar uma lista / tupla aos dois lados:

[1]+T+[2]
[1,*T,2]

(1,)+T+(2,)
(1,*T,2)

Imprimir o conteúdo de várias listas

Isso não se limita a print, mas é definitivamente de onde virá a maior parte da milhagem. O PEP448 agora permite a descompactação múltipla, da seguinte forma:

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

Atualizando vários itens do dicionário

Provavelmente isso não acontecerá com muita frequência, mas a sintaxe pode ser usada para economizar na atualização de dicionários se você estiver atualizando pelo menos três itens:

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

Isso basicamente nega qualquer necessidade dict.update.

Sp3000
fonte
6
Este parece pior do que Perl, mas funciona ...
Mega Man
20

Mude import *paraimport*


Se você não ouviu, import*salva caracteres!

from math import*

tem apenas 1 caractere mais longo import math as me você remove todas as instâncias dem.

Mesmo o uso de uma vez é uma poupança!

Timtech
fonte
19
>>> for i in range(x):s+=input()

se o valor de i é inútil:

>>> for i in[0]*x:s+=input()

ou

>>> exec's+=input();'*x
gmunkhbaatarmn
fonte
8
Você pode transformar o segundo exemplo em for i in[0]*x:s+=input()para economizar outro espaço. Além disso, você pode remover o espaço entre o exec ea primeira aspa para obterexec's+=input();'*x
Justin Peel
não deve a segunda linha ser:for i in[0]*x:s+=input()
micsthepick
Dupe (mais recente, mas mais upvotes)
#