Consigli per giocare a golf a Julia


20

Quali consigli generali hai per giocare a golf a Julia? Sto cercando idee che possano essere applicate ai problemi del codice golf in generale che siano almeno in qualche modo specifiche per Julia (ad esempio "rimuovere i commenti" non è una risposta).

Risposte:


19

NOTA: Di seguito possono contenere alcuni suggerimenti obsoleti, poiché Julia non è ancora del tutto stabilizzata in termini di struttura.

Alcuni trucchi per salvare alcuni personaggi

  1. Operatori di sovraccarico con funzioni binarie utilizzate di frequente . Ad esempio, se hai bisogno di fare molte divisioni intere e non hai bisogno di una divisione inversa, usa \ =dive puoi digitare a\binvece di div(a,b). Nota lo spazio: questo è necessario per evitarne l'analisi come operatore "\ =". Si noti inoltre che, se sovraccarico a livello di prompt REPL, utilizzare (\)=Base.(\)o \ =Base. \per ripristinarlo. NOTA: alcune funzioni sono esistenti UTF-8 operatori predefiniti, come ad esempio ÷per div, come notato da Alex A.
  2. Utilizzare ^ con stringhe per l'output condizionale . Cioè, piuttosto che a>0?"Hi":""usare "Hi"^(a>0)per salvare un byte, o per booleano a, usare "Hi"^aper salvare tre byte.
  3. (a volte) Conservare piccoli vettori di dimensioni fisse come variabili separate . Ad esempio, piuttosto che a=split("Hi there"," "), potresti essere in grado di evitare a[1]e a[2]utilizzando a,b=split("Hi there"," "), a cui si può fare riferimento come ae b, salvando tre byte per ogni utilizzo, al costo di soli due caratteri aggiuntivi al momento dell'assegnazione. Ovviamente, non farlo se puoi lavorare con operazioni vettoriali.
  4. Accedi al primo elemento dell'array con[] - per gli array, l'espressione A[]è equivalente a A[1]. Nota che questo non funziona per Stringhe se desideri ottenere il primo personaggio o per Tuple.
  5. Non usare isempty per array, tuple o stringhe - invece, usa ==[]per array e ==()tuple; allo stesso modo, per il negativo, usare !=[]e !=(). Per le stringhe, usa ==""per vuoto, ma usa >""per non vuoto, poiché "" è lessicograficamente prima di qualsiasi altra stringa.
  6. Utilizzare l'operatore booleano di corto circuito corretto al posto di "if" . Potrebbe essere un po 'meno specifico di Julia, ma vale la pena ricordare. x<=1&&"Hi"può essere scritto come x>1||"Hi", salvare un personaggio (purché il ritorno del booleano non sia importante).
  7. Non utilizzare contiene per verificare la presenza di caratteri nella stringa : se si è limitati all'ASCII di base, utilizzare in('^',s)anziché contains(s,"^"). Se è possibile utilizzare altri caratteri, è possibile salvare un po 'di più con '^'∈s, ma si noti che è 3 byte in UTF-8.
  8. Cerchi valori minimi / massimi in un array? Non usare il minimo o il massimo - piuttosto che usare minimum(x)o maximum(x), usare min(x...)o max(x...), per eliminare un carattere dal codice, se sai xche avrà almeno due elementi. In alternativa, se sai che tutti gli elementi di xsaranno non negativi, usa minabs(x)omaxabs(x)
  9. Laddove possibile e consentito dalla sfida, utilizzare una nuova riga effettiva anziché \ n - notare che ciò renderà più difficile la lettura del codice e potrebbe significare che è necessario fornire una versione "non controllata" per consentire alle persone di comprendere effettivamente esso.
  10. Inserisci le opzioni dopo la stringa regex - se vuoi avere una stringa regex in modalità multilinea, ad esempio, non digitare r"(?m)match^ this", digitare r"match^ this"m, salvando tre caratteri.
  11. Matrici 1-D inverse che utilizzano flipud : reverse(x)sono più lunghe di un byte flipud(x)e eseguiranno la stessa operazione, quindi quest'ultima è migliore.
  12. Ove possibile, utilizzare la concatenazione di array invece di push !, unshift !, append! Oppure anteporre! - per array normali, questo può essere fatto facilmente. Per le matrici di tipo Any con elementi di matrice, saranno necessarie parentesi graffe attorno alle matrici aggiunte (ovvero {[1,2]}, non {1,2}) - per Julia 0.4, sarebbe necessario Any[[1,2]].
  13. Usa l'indicizzazione di array per ottenere le dimensioni di un array o di una stringa : quando lo usi endall'interno dell'indicizzazione di array, viene automaticamente convertito nella lunghezza dell'array / della stringa. Quindi, anziché k=length(A)utilizzare, A[k=end]per salvare 3 caratteri. Nota che questo potrebbe non essere utile se vuoi usare k immediatamente. Questo funziona anche in un caso multidimensionale - A[k=end,l=end]otterrà la dimensione di ogni dimensione di A- tuttavia, (k,l)=size(A)in questo caso è più breve di un byte, quindi usalo solo se vuoi accedere immediatamente all'ultimo elemento contemporaneamente.
  14. Ottieni un iteratore di indice usando l'indicizzazione dell'array - Simile a 13, puoi anche ottenere un iteratore corrispondente alla lunghezza di un array usando A[k=1:end], nel qual caso kconterrà una corrispondenza iteratore 1:length(A). Ciò può essere utile quando si desidera utilizzare anche l'array Acontemporaneamente.
  15. Non usare collect per convertire una stringa in un array di caratteri , anziché collect(A)usare [A...], che farà la stessa cosa e salverà 4 byte.
  16. Hai bisogno di un numero convertito in una stringa? Utilizzare "$(s[i])"o dec(s[i])per espressioni o variabili a più caratteri e "$i"per variabili a carattere singolo.
  17. Utilizzare ?:invece di &&o ||per assegnazione condizionale - ovvero, se si desidera eseguire un'assegnazione solo su una condizione, è possibile salvare un byte scrivendo cond?A=B:1anziché cond&&(A=B), o cond?1:A=Bpiuttosto che cond||(A=B). Si noti che 1, qui, è un valore fittizio.
  18. Usa uniono invece diunique - union(s)farà la stessa cosa unique(s)e salverà un byte nel processo. Se puoi usare caratteri non ASCII, ∪(s)farà la stessa cosa e costa solo 3 byte anziché i 5 byte in union.

2
Oh come mi piacerebbe quel primo trucco in Python.
Seequ,

È possibile dividere gli spazi usando semplicemente split("Hi there")poiché l'argomento pattern viene impostato automaticamente su uno spazio.
Alex A.

@AlexA. - Lo so, ma non è il punto della punta e la punta si applica ugualmente bene in entrambi i modi.
Glen O

Il punto 12 è cambiato in 0.5.
Lyndon White,

@Oxinabox - Non sono sorpreso, sono abbastanza sicuro che alcuni di loro siano ormai obsoleti. Inizialmente ho scritto la maggior parte dei suggerimenti per la 0.3, credo.
Glen O

15

Ridefinire gli operatori per definire le funzioni

La ridefinizione degli operatori può far risparmiare parecchi byte tra parentesi e virgole.

Operatori unari ricorsivi

Per un esempio unario, confronta le seguenti implementazioni ricorsive della sequenza di Fibonacci:

F(n)=n>1?F(n-1)+F(n-2):n # 24 bytes
!n=n>1?!~-n+!(n-2):n     # 20 bytes
!n=n>1?!~-n+!~-~-n:n     # 20 bytes

Provalo online!

L'operatore ridefinito mantiene la sua precedenza iniziale.

Nota che non potremmo semplicemente scambiarci !a favore ~, poiché ~è già definito per gli interi, mentre !è definito solo per i booleani.

Operatori binari

Anche senza ricorsione, la ridefinizione di un operatore è più breve della definizione di una funzione binaria. Confronta le seguenti definizioni di un semplice test di divisibilità.

f(x,y)=x==0?y==0:y%x==0 # 23 bytes
(x,y)->x==0?y==0:y%x==0 # 23 bytes
x->y->x==0?y==0:y%x==0  # 22 bytes
x\y=x==0?y==0:y%x==0    # 20 bytes

Provalo online!

Operatori binari ricorsivi

Di seguito viene illustrato come ridefinire un operatore binario per calcolare la funzione Ackermann:

A(m,n)=m>0?A(m-1,n<1||A(m,n-1)):n+1    # 35 bytes
^ =(m,n)->m>0?(m-1)^(n<1||m^~-n):n+1   # 36 bytes
| =(m,n)->m>0?m-1|(n<1||m|~-n):n+1     # 34 bytes
m\n=m>0?~-m\(n<1||m\~-n):n+1           # 28 bytes

Provalo online!

Si noti che ^è ancora più lungo rispetto all'utilizzo di un identificatore regolare, poiché la sua precedenza è troppo elevata.

Come menzionato prima

m|n=m>0?m-1|(n<1||m|~-n):n+1           # 28 bytes

non funzionerebbe per argomenti interi, poiché |è già definito in questo caso. La definizione per numeri interi può essere modificata con

m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes

ma è proibitivamente lungo. Tuttavia, esso fa lavoro se si passa un galleggiante come argomento sinistro e un intero come argomento di destra.


11
  1. Non lasciarti sedurre troppo facilmente dal fattore (n) La tentazione della libreria di base base factor(n)ha un difetto fatale: restituisce la fattorizzazione del tuo numero intero in un Dicttipo non ordinato . Pertanto, richiede costosi collect(keys())e collect(values())potenzialmente anche a cate a sortper ottenere i dati desiderati da esso. In molti casi, può essere più economico considerare solo la divisione di prova. Triste ma vero.

  2. Utilizzare la mappa map è un'ottima alternativa al looping. Essere consapevoli della differenza tra mape map!e sfruttare la funzionalità sul posto di quest'ultimo quando è possibile.

  3. L'uso di mapreduce mapreduce estende ulteriormente la funzionalità di map e può essere un notevole risparmio di byte.

  4. Le funzioni anonime sono fantastiche! .. specialmente quando passato alle mapfunzioni di cui sopra .

  5. Le funzioni cumulative della matrice cumprod , le funzionicumsum saporite cummine le altre denominate in modo simile consentono operazioni cumulative lungo una dimensione specificata di una matrice n-dimensionale. (O * un * specificato se l'array è 1-d)

  6. Notazione breve per Qualsiasi Quando si desidera selezionare tutte le dimensioni particolari di un array multidimensionale (o Dict), ad esempio A[Any,2], è possibile salvare byte utilizzandoA[:,2]

  7. Utilizzare la notazione a riga singola per le funzioni Invece di function f(x) begin ... endsemplificare spessof(x)=(...)

  8. Usa l'operatore ternario Può essere un salvaspazio per costruzioni If-Then-Else a singola espressione. Avvertenze: sebbene possibile in alcune altre lingue, non è possibile omettere la parte dopo i due punti in Julia. Inoltre, l'operatore è a livello di espressione in Julia, quindi non è possibile utilizzarlo per l'esecuzione condizionale di interi blocchi di codice.
    if x<10 then true else false endvs
    x<10?true:false


3
Come diavolo è "usare l'operatore ternario" in qualche modo specifico per Julia? È rilevante per ogni lingua che lo possiede.
Peter Taylor,

5
È rilevante che ce l'abbia. Molte lingue hanno anche funzioni cartografiche, anonime o pure, una sorta di scorciatoia per qualsiasi / tutte, funzioni cumulative, ecc. Se dovessimo ridurre ogni thread di suggerimenti solo alle funzionalità assolutamente uniche di quella lingua, ci sarebbero pochissimi contenuti di suggerimenti .
Jonathan Van Matre,

3
Accidenti, solo quelli funzionali per i principianti, in cui tutto restituisce un valore, quindi un'operazione ternaria sarebbe ridondante. Se devi avere esempi specifici: Go, Haskell, Scala, Lua, VB, Prolog, PL / SQL ... anche Python non ha funzionato per molte versioni. Delle quasi dodici lingue le cui punte di suggerimenti menzionano il loro operatore ternario, c'è qualche motivo per cui hai scelto di diventare provinciale solo nelle mie?
Jonathan Van Matre,

3
Bene, ehi, almeno sei un ciarlatano di pari opportunità. ヘ ( ̄ ー  ̄ ヘ)
Jonathan Van Matre

1
Potrei suggerire di regolare il suggerimento 3? mapreduce è più lungo di mapfoldl o mapfoldr e può avere comportamenti variabili a seconda dell'implementazione. mapfoldl e mapfoldr sono associati rispettivamente a sinistra e a destra (rispettivamente), e quindi sono una scelta migliore. Questo vale anche più in generale per ridurre (usare foldl o foldr).
Glen O

9

Scorrere le funzioni

Ciò è possibile anche in altre lingue, ma in genere è più lungo del metodo semplice. Tuttavia, la capacità di Julia di ridefinire i suoi operatori unari e binari lo rende piuttosto golfoso.

Ad esempio, per generare la tabella di addizione, sottrazione, moltiplicazione e divisione per i numeri naturali da 1 a 10, è possibile utilizzare

[x|y for x=1:10,y=1:10,| =(+,-,*,÷)]

che ridefinisce il binario operatore |come +, -, *e ÷, quindi calcola x|yper ciascuna operazione e xe ynegli intervalli desiderati.

Questo funziona anche per gli operatori unari. Ad esempio, per calcolare i numeri complessi 1 + 2i , 3-4i , -5 + 6i e -7-8i , i loro negativi, i loro coniugati complessi e i loro inversi moltiplicativi, si potrebbe usare

[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]

che ridefinisce la unario operatore ~come +, -, conje inv, quindi calcola ~xper tutti i numeri complessi desiderati.

Esempi in concorsi reali


6
  1. Le parole chiave a volte possono seguire immediatamente le costanti senza la necessità di spazio o punto e virgola. Per esempio:

    n->(for i=1:n n-=1end;n)

    Nota la mancanza di uno spazio tra 1e end. Ciò vale anche per il endverificarsi di un paren vicino, ad es )end.

  2. Esegue la divisione dei numeri interi usando ÷piuttosto che div()o sovraccaricando un operatore. Si noti che ÷vale 2 byte in UTF-8.

  3. Utilizzare vec()o A[:](per alcuni array A) anziché reshape()quando possibile.

  4. Crea funzioni anziché programmi completi quando consentito nelle regole di sfida. È più breve definire una funzione che accetta input piuttosto che definire variabili leggendo da stdin. Per esempio:

    n->(n^2-1)
    n=read(STDIN,Int);n^2-1
  5. Le variabili possono essere incrementate all'interno dell'argomento in una funzione. Ad esempio, la seguente è la mia risposta alla sfida Trova il prossimo numero binario 1-Sparse :

    n->(while contains(bin(n+=1),"11")end;n)

    Questo è più breve dell'incremento nall'interno del loop.


6
  1. Non digitarereturn f(x)=x+4 è identico a ma più breve di f(x)=return x+4. Julia restituisce sempre il risultato dell'ultima istruzione.
  2. Usa = invece di in . [x for x in 1:4]è di 3 caratteri più lungo di, ma equivalente a[x for x=1:4]

5

Utilizzare le chiamate di funzione di trasmissione.

Introdotto in Julia 0.5. È come una mappa, ma usa meno caratteri e trasmette il comportamento di trasmissione sui suoi argomenti, il che significa che puoi scrivere meno lambda per gestire le cose.

Piuttosto che:

  • map(f,x) - 8 caratteri.
  • f.(x) - 5 caratteri

Meglio ancora:

  • map(a->g(a,y),x) - 16 caratteri
  • g.(x,[y]) - 9 caratteri
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.