Suggerimenti per giocare a golf in Python


248

Quali consigli generali hai per giocare a golf in Python? Sto cercando idee che possano essere applicate ai problemi del code-golf e che siano almeno in qualche modo specifiche per Python (es. "Rimuovere i commenti" non è una risposta).

Si prega di inviare un suggerimento per risposta.


27
Oh, posso vedere una serie di domande come questa in arrivo per ogni lingua ...
R. Martinho Fernandes,

4
@Marthinho sono d'accordo. Ho appena iniziato un equivalente C ++ . Non penso che sia una cosa negativa, purché non vediamo le stesse risposte ripubblicate in molti di questi tipi di domande.
marcog,

50
Adoro la domanda ma devo continuare a ripetermi "questo è SOLO per divertimento NON per codice di produzione"
Greg Guida,

2
Questa domanda non dovrebbe essere un post wiki della community?
Dorukayhan,

3
@dorukayhan Nope; si tratta di un valido codice di-golf punte domanda chiedendo suggerimenti su come abbreviare pitone codice per scopi CG'ing. Tali domande sono perfettamente valide per il sito e nessuno di questi tag dice esplicitamente che la domanda dovrebbe essere in CW, a differenza di SO, che ha richiesto che le sfide CG fossero in CW. Inoltre, scrivere una buona risposta e trovare tali suggerimenti merita sempre qualcosa, che viene tolto se la domanda è wiki della comunità (rappresentante).
Erik the Outgolfer,

Risposte:


152

Usa a=b=c=0invece di a,b,c=0,0,0.

Usa a,b,c='123'invece di a,b,c='1','2','3'.


2
questo è un bel consiglio in generale :)

28
Si noti che questo non funzionerà necessariamente per la definizione di oggetti mutabili che verranno modificati sul posto. a = b = [1] è in realtà diverso da a = [1]; b = [1]
isaacg

6
La cosa divertente del primo consiglio è che funziona anche in Java.
Giustino, il

1
@Justin Sì, ma solo con tipi primitivi
HyperNeutrino,

11
MAI utilizzare a = b = c = [] o qualsiasi istanza di oggetto poiché tutte le variabili punteranno alla stessa istanza. Probabilmente non è quello che vuoi.
PhE

146

I condizionali possono essere lunghi. In alcuni casi, è possibile sostituire un semplice condizionale con (a,b)[condition]. Se conditionè vero, bviene restituito.

Confrontare

if a<b:return a
else:return b

A questo

return(b,a)[a<b]

37
Questi non sono esattamente gli stessi. Il primo valuta solo l'espressione che viene restituita, mentre il secondo li valuta sempre entrambi. Questi sono in corto circuito: a if a<b else bea<b and a or b
marinus

3
(lambda(): b, lambda(): a)[a < b]()crea il tuo corto circuito con lambdas
Ming-Tang

3
@marinus, non sono uguali: considera solo P and A or Bper A che dà bool(A)=False. Ma (P and [A] or [B])[0]farà il lavoro. Vedi diveintopython.net/power_of_introspection/and_or.html per riferimento.
kgadek,

6
Le lambda sono molto più lunghe di un'espressione condizionale.
user2357112

18
@ user2357112 Ma ti fanno sembrare molto più fresco quando li usi. :]
Chase Ries

117

Una grande cosa che ho fatto una volta è:

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

invece di:

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

Gli operatori di confronto di Python oscillano.


Usando che tutto è paragonabile in Python 2, puoi anche evitare l' andoperatore in questo modo. Ad esempio, se a, b, ce dsono numeri interi,

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

può essere abbreviato da un personaggio per:

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

Questo utilizza che ogni elenco è più grande di qualsiasi numero intero.

Se ce dsono liste, questo migliora ancora:

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

22
Ovviamente se questo fosse effettivamente giocato a golf sarebbe3>a>1<b<5
Rafe Kettler il

4
Adoro la simmetria. Mi ricorda il vecchio trucco del golf Perl per trovare il minimo di $ ae $ b: [$a => $b]->[$b <= $a]:)
Simon Whitaker,

Si noti che il secondo esempio (senza elenchi) può essere fatto anche conif(a<b)+(c>d):foo()
WorldSEnder

6
Il + dovrebbe essere a *. Un orsarebbe+
WorldSEnder

1
foo()if 3>a>1<b<5
Erik the Outgolfer,

103

Se si utilizza ripetutamente una funzione integrata, potrebbe essere più efficiente in termini di spazio assegnarle un nuovo nome, se si utilizzano argomenti diversi:

r=range
for x in r(10):
 for y in r(100):print x,y

6
In realtà non ha salvato alcun byte, però.
user2357112

4
r = range e le altre due r sono 9 caratteri; l'utilizzo dell'intervallo due volte è di 10 caratteri. Non un grande risparmio in questo esempio, ma basterebbe un ulteriore uso del range per vedere un notevole risparmio.
Frank,

13
@Frank La nuova riga aggiuntiva è un altro personaggio.
L3viathan,

2
In effetti, due ripetizioni sono troppo piccole per salvare un nome di cinque funzioni di lunghezza. Hai bisogno di: lunghezza 2: 6 ripetizioni, lunghezza 3: 4 ripetizioni, lunghezza 4 o 5: 3 ripetizioni, lunghezza> = 6: 2 ripetizioni. AKA (lunghezza-1) * (ripetizioni-1)> 4.
Ørjan Johansen,

Nota che questo è applicabile a tutte le lingue con funzioni di prima classe.
bfontaine,

94

A volte il tuo codice Python richiede di avere 2 livelli di rientro. La cosa ovvia da fare è usare uno e due spazi per ogni livello di rientro.

Tuttavia, Python 2 considera i caratteri di tabulazione e spazio come livelli di rientro diversi.

Ciò significa che il primo livello di rientro può essere uno spazio e il secondo può essere un carattere di tabulazione.

Per esempio:

if 1:
 if 1:
\tpass

Dov'è \til carattere di tabulazione.


1
Fantastico, non ci ho mai pensato!
Jules Olléon,

97
Questo fallisce in python3: non puoi più mescolare spazi e tabulazioni (una cosa negativa per codegolf, ma una cosa buona in tutti gli altri casi).
Bakuriu,

1
In Python 3.4 questo sembra funzionare bene.
trichoplax,

3
@trichoplax , In python 3.4.3 I getTabError: inconsistent use of tabs and spaces in indentation.
ceilingcat

Per riferimento, una scheda vale 8 spazi.
Erik the Outgolfer,

87

Usa la sostituzione di stringhe e execgestisci parole chiave lunghe come quelle lambdache si ripetono spesso nel tuo codice.

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

La stringa di destinazione è molto spesso 'lambda ', che è lunga 7 byte. Supponiamo che il tuo frammento di codice contenga noccorrenze di 'lambda ', ed è slungo byte. Poi:

  • L' plainopzione è slunga byte.
  • L' replaceopzione è s - 6n + 29lunga byte.
  • L' %opzione è s - 5n + 22 + len(str(n))lunga byte.

Da una trama di byte salvati suplain per queste tre opzioni, possiamo vedere che:

  • Per n <5 lambda, è meglio non fare niente di speciale.
  • Per n = 5 , la scrittura exec"..."%(('lambda ',)*5)salva 2 byte ed è l'opzione migliore.
  • Per n> 5 , la scrittura exec"...".replace('`','lambda ')è l'opzione migliore.

Per altri casi, è possibile indicizzare la tabella seguente:

          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)

Ad esempio, se la stringa lambda x,y:(lunghezza 11) si presenta 3 volte nel codice, è meglio scrivere exec"..."%(('lambda x,y:',)*3).


4
questo dovrebbe ottenere più voti, è un consiglio molto utile.
bigblind

7
è estremamente raro che funzioni . il costo di replaceè enorme.
stand dal

4
Quando funziona, però, aiuta molto.
undergroundmonorail

Interessante, mai nemmeno pensato!
Claudiu,

Ho aggiunto un nuovo operatore per lambda nella mia lingua basato su Python: =>è solo la stringa = lambda . Ad esempio, f=>:0sarebbe f = lambda: 0.
NoOneIsHere

78

Utilizzare la divisione estesa per selezionare una stringa tra molte

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

In questo caso booleano a due stringhe, si può anche scrivere

b*"string"or"other_string"

per

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

A differenza dell'interlacciamento, questo funziona per stringhe di qualsiasi lunghezza, ma può avere problemi di precedenza dell'operatore se bè invece un'espressione.


Si noti che il primo esempio ha esattamente la stessa lunghezza difor x in ("foo","bar","baz"): print x
Mateen Ulhaq,

1
@MateenUlhaq, Questo è solo un esempio di come vengono visualizzati i diversi valori di x. La parte golfata è il "fbboaaorz"[x::3]vs ["foo","bar","baz"][x]Come il xvalore è derivato sarebbe un'altra parte della tua soluzione golf.
Gnibbler,

72

Utilizzare `n`per convertire un numero intero in una stringa anziché utilizzare str(n):

>>> n=123
>>> `n`
'123'

38
Bello, ma non funziona con Python3.
Alexandru,

2
Attenzione: funziona davvero per numeri interi, ma non per stringhe, ad esempio.
Nakilon,

41
btw. `` è l'abbreviazione di repr
Alexandru,

9
I numeri interi inferiori a -2 ** 31 o superiori a 2 ** 31-1 (Longs) ricevono una "L" alla fine.
hallvabo,

6
Questo può anche essere usato per stampare i galleggianti con la massima precisione
Gnibbler,

69

Memorizza le tabelle di ricerca come numeri magici

Supponi di voler codificare una tabella di ricerca booleana, ad esempio quale dei primi dodici numeri inglesi contiene un 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

Quindi, puoi implementare questa tabella di ricerca in modo conciso come:

3714>>i&1

con il risultato 0o 1uguale Falsea True.

L'idea è che il numero magico memorizzi la tabella come una stringa di bit bin(3714)= 0b111010000010, con la n-esima cifra (dalla fine) corrispondente alla nvoce della tabella th. Accediamo la nvoce di th da bitshifting il numero nspazi a destra e prendere l'ultima cifra da &1.

Questo metodo di archiviazione è molto efficiente. Confronta con le alternative

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

Puoi fare in modo che la tua tabella di ricerca memorizzi voci multibit che possono essere estratte come

 340954054>>4*n&15

per estrarre il relativo blocco a quattro bit.


Potremmo avere un risultato di esempio per il blocco a quattro bit? Hai usato una regola per il blocco n-bit?
JeromeJ,

8
L'esagono a volte potrebbe essere ancora più piccolo.
Joonazan,

4
Questo è utile per molte lingue.
Cyoce,

1
@Joonazan Hex è più piccolo per i numeri superiori a 999 999 .
Mateen Ulhaq,

60

Comprimi due anelli numerici in uno

Supponiamo che stai ripetendo le celle di una m*ngriglia. Invece di due forloop nidificati , uno per la riga e uno per le colonne, in genere è più breve utilizzare un singolo loop per scorrere le m*ncelle della griglia. È possibile estrarre la riga e la colonna della cella all'interno del ciclo.

Codice originale:

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

Codice golfizzato:

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

In effetti, stai ripetendo il prodotto cartesiano delle due gamme, codificando la coppia (i,j)come x=i*n+j. Hai salvato una rangechiamata costosa e un livello di rientro all'interno del ciclo. L'ordine di iterazione è invariato.

Usa //invece che /in Python 3. Se ti riferisci a ie jmolte volte, potrebbe essere più veloce assegnare i loro valori i=k/n, j=k%nall'interno del loop.


5
Questo e spettacolare. Non avevo mai capito che fosse possibile!
theonlygusti,

Ho visto questo nei suggerimenti per JavaScript. È un trucco piuttosto utile nella maggior parte delle lingue.
Cyoce,

7
Per riferimento, per estenderlo a 3 loop:for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
mbomb007,

3
Per i nloop: repl.it/EHwa
mbomb007,

In alcuni casi, itertools.productpuò essere molto più conciso dei loop nidificati, specialmente quando si generano prodotti cartesiani. a1, a2, b1, b2sono esempi del prodotto cartesiano di 'ab'e'12'
Aaron3468

54

A meno che il seguente token non inizi con eo E. È possibile rimuovere lo spazio seguendo un numero.

Per esempio:

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

diventa:

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

L'uso di questo in complicate istruzioni di una riga può far risparmiare parecchi caratteri.

EDIT: come ha sottolineato @marcog, 4or afunzionerà, ma non a or4perché questo viene confuso con un nome di variabile.


37
if(i,j)==(4,4):è ancora più breve e in questo caso specialeif i==j==4:
gnibbler il

3
Correlati: 4or afunziona, ma nona or4
marcog

17
0orinoltre non funziona ( 0oè un prefisso per i numeri ottali).
Nabb,

5
@Nabb Non importa comunque, dato che 0 or xtornerà sempre x. Potrebbe anche tagliare il 0 or.
6ıʇǝɥʇuʎs

5
0orva bene come parte di un numero più lungo però. 10 or xè equivalente a 10or x.
trichoplax,

54

Per intero n, puoi scrivere

  • n+1 come -~n
  • n-1 come ~-n

perché il bit flip è ~xuguale -1-x. Questo utilizza lo stesso numero di caratteri, ma può tagliare indirettamente spazi o parentesi per la precedenza dell'operatore.

Confrontare:

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

Gli operatori ~e le unari -sono precedenza maggiore rispetto *, /, %, a differenza di binario +.


11
Una variante di questo trucco ho incontrato oggi: -~-xsalva uno contro byte (1-x).
Lynn,

4
Un'altra utile applicazione è che a+b+1può essere scritta in modo più conciso a-~b.
Strigoides,

Ed n-i-1è giusto n+~i.
ruohola,

51

Un bel modo per convertire un iterabile all'elenco su Python 3 :

immagina di avere un po 'iterabile, come

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

Ma hai bisogno di un elenco:

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

È molto utile creare un elenco di caratteri da una stringa

s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'

1
digitando *s,='abcde'e poi si sblocca il mio python3 interattivo con un segfault :(
daniero

@daniero Wow. Solo sulla console interattiva? Sembra molto strano. Provalo su una console pulita o segnala il bug
JBernardo

1
My Python 3.5 funziona bene.
NoOneIsHere

per i = (x ** 2 per x nell'intervallo (5)) Ottengo questo codice restituito <oggetto generatore <genexpr> a 0x03321690>
george,

7
E se lo stai facendo in un'espressione, puoi farlo [*'abcde'].
Esolanging Fruit,

46

Invece di range(x), puoi usare l' *operatore in un elenco di qualsiasi cosa, se in realtà non hai bisogno di usare il valore di i:

for i in[1]*8:pass

al contrario di

for i in range(8):pass

Se è necessario farlo più di due volte, è possibile assegnare qualsiasi iterabile a una variabile e moltiplicare quella variabile per l'intervallo desiderato:

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

Nota : questo è spesso più lungo di exec"pass;"*8, quindi questo trucco dovrebbe essere usato solo quando non è un'opzione.


@proudhaskeller Penso che il punto della linea che hai rimosso fosse che "Oltre agli ovvi risparmi di carattere che ottieni perché [1]*8è più breve di range(8), puoi anche salvare uno spazio perché for i in[...è legale mentre for i in range...non lo è".
undergroundmonorail,

oh, giusto, non l'ho capito. risolto ora
orgoglioso haskeller il

7
exec"pass;"*8è significativamente più breve.
DJMcMayhem

1
se r=1, r*8è di 8, e non si può scorrere un numero. Immagino volessi direr=[1]
Artemis Fowl il

1
@ArtemisFowl, no va bene così com'è, la virgola dopo 1 crea una tupla che è iterabile.
sasha,

43

Puoi usare la buona vecchia faccina aliena per invertire le sequenze:

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

38

Disimballaggio iterabile esteso ("Assegnazione speciali", solo Python 3)

Il modo migliore per spiegare questo è tramite un esempio:

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

Abbiamo già visto un uso per questo: trasformare un iterabile in un elenco in Python 3 :

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

Ecco alcuni altri usi.

Ottenere l'ultimo elemento da un elenco

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

In alcune situazioni, questo può essere utilizzato anche per ottenere il primo elemento da salvare su parentesi:

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

Assegnare un elenco vuoto e altre variabili

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

Rimozione del primo o dell'ultimo elemento di un elenco non vuoto

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

Questi sono più brevi rispetto alle alternative L=L[1:]e L.pop(). Il risultato può anche essere salvato in un altro elenco.

Suggerimenti per gentile concessione di @grc


Wow! Ho scritto a=1;L=[]tante volte. È sorprendente poter salvare caratteri su qualcosa di così semplice.
xnor

@xnor Quello è grazie a grc. Con solo un altro elemento non è altrettanto buono ( a,*L=1,), ma salva comunque un carattere :)
Sp3000,

non dimenticare che puoi anche ottenere sia il primo che l'ultimo elemento di un elenco cona,*_,b=L
Cyoce

36

impostare letterali in Python2.7

Puoi scrivere set come questo S={1,2,3}Ciò significa anche che puoi verificare l'appartenenza usando {e}&Sinvece di e in Squale salva un carattere.


4
E questo salva anche il personaggio in ifs poiché non ci sono spazi ( if{e}&S:)
Artyer il

1
Si noti che è possibile sostituire not incon {e}-Scon quel trucco
Il gufo nero Kai

35

Per anni mi ha infastidito il fatto che non potessi pensare a un modo breve per ottenere l'intero alfabeto. Se usi rangeabbastanza che R=rangevale la pena avere nel tuo programma, allora

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

è più breve dell'ingenuo

'abcdefghijklmnopqrstuvwxyz'

, ma per il resto è più lungo di un singolo personaggio. Mi perseguitava il fatto che quello intelligente che richiedeva una certa conoscenza dei valori ASCII finisse per essere più prolisso che scrivere semplicemente tutte le lettere.

Fino a quando non ho visto questa risposta per l'alfabeto di mia figlia . Non riesco a seguire abbastanza bene la cronologia delle modifiche per capire se questo genio fosse opera dell'OP o se fosse un suggerimento di un commentatore, ma questo è (credo) il modo più breve per creare un iterabile delle 26 lettere nell'alfabeto romano.

map(chr,range(97,123))

Se il caso non ha importanza, puoi rimuovere un altro carattere usando le lettere maiuscole:

map(chr,range(65,91))

Uso maptroppo, non so come questo non mi sia mai venuto in mente.


4
Potrei usarlo nel vero codice, mi sento così stupido quando codifico queste cose: ')
ToonAlfrink

37
Nella codifica effettiva, usa string.lowercase- ecco a cosa serve.
Kevin S,

1
se hai bisogno di entrambi i casi, il modo più breve che conosco è filter (str.isalpha, map (chr, range (256))). È appena più breve di s = map (chr, range (256)); s + = map (str.lower, s)
quintopia,

@quintopia: Perché 256 anziché 122 ( ord('z'))? A parte la stessa lunghezza ... Inoltre, se hai bisogno di caratteri alfanumerici, sostituisci str.isalphanella versione di @ quintopia con str.isalnum. (Ma se hai solo bisogno di un caso, l'intera stringa di 36 caratteri non è più lunga di filter(str.isalnum,map(chr,range(90))).)
Tim Pederick il

2
Se stai per essere ingiusto e usi il range come R, la mia versione è più corta di quella originale: '%c'*26%tuple(R(97,123))(solo 24 caratteri) se si scrive rangeè lunga quanto l'alfabeto - la versione maiuscola è più corta
JBernardo

32

Sebbene Python non abbia istruzioni switch, è possibile emularle con dizionari. Ad esempio, se si desidera un passaggio come questo:

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

È possibile utilizzare le ifistruzioni oppure è possibile utilizzare questo:

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

o questo:

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

che è meglio se tutti i percorsi di codice sono funzioni con gli stessi parametri.

Per supportare un valore predefinito, procedere come segue:

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

(o questo:)

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

Un altro vantaggio di questo è che se si hanno ridondanze, è possibile aggiungerle solo dopo la fine del dizionario:

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

E se volessi semplicemente utilizzare un interruttore per restituire un valore:

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

Potresti semplicemente fare questo:

getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)

2
Questo è qualcosa che prenderei in seria considerazione l'utilizzo in natura. Mi mancano così le mie dichiarazioni switch! +1
HalosGhost

1
Sebbene invece di usare un dizionario con chiavi numerate nel primo esempio, dovresti semplicemente usare un elenco
Cyoce

1
Se hai le stringhe come chiavi, usa dict(s1=v1,s2=v2,...,sn=vn)invece di {'s1':v1,'s2':v2,...,'sn':vn}salvare 2 * n-4 byte ed è meglio se n> = 3
Black Owl Kai

31

Quando hai due valori booleani ae b, se vuoi scoprire se entrambi ae bsono veri, usa *invece di and:

if a and b: #7 chars

vs

if a*b: #3 chars

se uno dei due valori è falso, verrà valutato come 0in tale istruzione e un valore intero è vero solo se è diverso da zero.


9
Oppure si potrebbe usare &: a=b=False,a&b
ɐɔıʇǝɥʇuʎs

3
utilizzare +per orse è possibile garantirea != -b
undergroundmonorail

2
|funziona in tutte le situazioni.
CalculatorFeline

1
*anziché and/ &&salva alcuni byte in molte lingue.
wastl,

26

Sfrutta le rappresentazioni di stringa di Python 2

Python 2 ti consente di convertire un oggetto xnella sua rappresentazione di stringa `x`al costo di soli 2 caratteri. Utilizzare questo per attività che sono più facili da eseguire sulla stringa dell'oggetto rispetto all'oggetto stesso.

Unisciti ai personaggi

Dato un elenco di caratteri l=['a','b','c'], si può produrre ''.join(l)come `l`[2::5], che salva un byte.

Il motivo è che `l`è "['a', 'b', 'c']"(con spazi), quindi è possibile estrarre le lettere con una sezione di elenco, iniziando dal secondo carattere con indice zero ae prendendo ogni quinto carattere da lì. Questo non funziona per unire stringhe multi-carattere o caratteri di escape rappresentati come '\n'.

Cifre concatenate

Allo stesso modo, dato un elenco non vuoto di cifre come l=[0,3,5], si possono concatenarle in una stringa '035'come `l`[1::3].

Questo risparmia facendo qualcosa di simile map(str,l). Si noti che devono essere cifre singole e non possono avere float come 1.0mischiati. Inoltre, ciò non riesce nella lista vuota, producendo ].

Controlla gli aspetti negativi

Ora, per un'attività non stringa. Supponiamo di avere un elenco ldi numeri reali e di voler verificare se contiene numeri negativi, producendo un valore booleano.

Tu puoi fare

'-'in`l`

che verifica la presenza di un segno negativo nella stringa rep. Questo più breve di uno dei due

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

Per il secondo, min(l)<0fallirebbe sulla lista vuota, quindi devi coprirti.


La concatenazione dell'affilatura di stringhe di singole cifre è efficace anche in Python 3, anche se in misura minore: str(l)[2::5]è di 12 byte, contro 19 per ''.join(map(str,l)). Una situazione reale in cui è emersa (dove lera un'istruzione del generatore, non un elenco) mi ha salvato solo un byte ... che ne vale ancora la pena!
Tim Pederick,

25

Una funzione a una riga può essere eseguita con lambda:

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

può essere convertito in (notare lo spazio mancante 3ande 10or)

c=lambda a:a<3and a+10or a-5

21
oppure c=lambda a:a+[-5,10][a<3]. il trucco e / o è più utile quando si dipende dal comportamento del cortocircuito
gnibbler

3
Nella tua funzione, else: può essere eliminato poiché returninterrompe l'esecuzione della funzione, quindi tutto ciò che segue viene eseguito solo se la ifcondizione non è riuscita, ovvero se la elsecondizione è vera. Quindi elsepuò essere tranquillamente ommited. (Spiegato in dettaglio per i neofiti là fuori)
JeromeJ

c (-10) restituisce -15 mentre dovrebbe restituire 0
Anvit

oppurec=lambda a:a-5+15*(a<3)
JayXon l'

25

i loop fino a 4 articoli potrebbero essere meglio per fornire una tupla invece di usare la gamma

for x in 0,1,2:

vs

for x in range(3):

24

Ceil e pavimento

Se mai vuoi ottenere il risultato arrotondato per divisione, proprio come faresti con //floor, potresti usare math.ceil(3/2)per 15 o molto più breve -(-3//2)per 8 byte.

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

math.ceil(n)    : 12 bytes+12 for import
-(-n//1)        : 8  bytes

5
Questo mi ha appena salvato vicino a 20 byte, grazie!
Morgan Thrapp,

1
a volte puoi n//1+1cavartela invece di ceil ma significa ceil (n) = n + 1 ma dovrebbe funzionare per tutti i valori non interi
fejfo

round(x)è (x+.5)//1, +1 byte, ma quest'ultimo inizia con a (, e se xè una somma costituita da una costante può essere utile.
user202729,

23

Utilizzare +=invece di appendeextend

A.append(B)  

può essere abbreviato in:

A+=B,

B,qui crea una tupla a un elemento che può essere usata per estendere Aproprio come [B]in A+=[B].


A.extend(B)

può essere abbreviato in:

A+=B

5
In molti (ma non in tutti) casi, return 0o return 1è equivalente a return Falseo return True.
undergroundmonorail

5
(1) funziona solo se sai già che il numero è negativo, nel qual caso puoi salvare altri 2 caratteri semplicemente usando un segno meno. -xpiuttosto che x*-1. --8.32piuttosto che -8.32*-1. O solo 8.32...
trichoplax,

Citando l'OP: si prega di inviare un suggerimento per risposta.
nyuszika7h,

Si noti che in A+=B Bè a tuple.
Erik the Outgolfer,

23

Scelta di uno dei due numeri in base a una condizione

Sai già di usare la selezione della lista [x,y][b]con un booleano bper l'espressione ternaria y if b else x. Le variabili x, ye bpossono anche essere espressioni, però notare che sia xe yvengono valutati anche quando non è stato selezionato.

Ecco alcune potenziali ottimizzazioni quando xe ysono numeri.

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

È anche possibile cambiare xe yse è possibile riscrivere bper essere invece la sua negazione.


22

Usa ~ per indicizzare dal retro di un elenco

Se Lè un elenco, utilizzare L[~i]per ottenere l' ielemento th dal retro.

Questo è l i'elemento del rovescio di L. Il complemento di bit è ~iuguale -i-1e quindi corregge l'errore off-by-one da L[-i].


21

PEP448 - Generalizzazioni aggiuntive sul disimballaggio

Con il rilascio di Python 3.5 , la manipolazione di liste, tuple, set e dicts è appena diventata più golfista.

Trasformare un iterabile in un set / elenco

Confronta le coppie:

set(T)
{*T}

list(T)
[*T]

tuple(T)
(*T,)

Molto più breve! Si noti, tuttavia, che se si desidera convertire qualcosa in un elenco e assegnarlo a una variabile, la decompressione iterabile estesa normale è più breve:

L=[*T]
*L,=T

Una sintassi simile funziona per le tuple:

T=*L,

che è come decomprimere iterabile esteso, ma con l'asterisco e la virgola sull'altro lato.

Elenchi / tuple uniti

Il disimballaggio è leggermente più breve della concatenazione se è necessario aggiungere un elenco / tupla ad entrambi i lati:

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

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

Stampa dei contenuti di più elenchi

Questo non si limita a print, ma è sicuramente da dove arriverà la maggior parte del chilometraggio. PEP448 ora consente il disimballaggio multiplo, in questo modo:

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

Aggiornamento di più voci del dizionario

Questo probabilmente non accadrà molto spesso, ma la sintassi può essere utilizzata per salvare sull'aggiornamento dei dizionari se stai aggiornando almeno tre elementi:

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

Questo praticamente nega qualsiasi necessità dict.update.


6
Sembra peggio di Perl, ma funziona ...
Mega Man

20

Cambia import *inimport*


Se non l'hai sentito, import*salva i caratteri!

from math import*

è solo 1 carattere più lungo di import math as me puoi rimuovere tutte le istanze dim.

Anche un solo utilizzo è un risparmio!


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

se il valore di i è inutile:

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

o

>>> exec's+=input();'*x

8
Puoi creare il secondo esempio in for i in[0]*x:s+=input()per salvare un altro spazio. Inoltre, puoi rimuovere lo spazio tra il exec e la prima virgoletta da ottenereexec's+=input();'*x
Justin Peel,

la seconda riga non dovrebbe essere:for i in[0]*x:s+=input()
micsthepick,

Dupe (più recente ma più votato)
user202729
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.