Suggerimenti per il golf a Mathematica


41

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

Risposte:


30

I suggerimenti di seguito variano dal più economico al più usato:

  1. Usa i comandi di alto livello di Mathematica ove possibile, anche quelli voluminosi:

  2. Utilizzare Graphics and Textper Ascii art: ad es. Programmazione a stella! e costruisci un orologio analogico

  3. Simboli dedicati:

    • simboli di operazioni logiche e impostate anziché i nomi delle loro forme lunghe: ⋂, ⋃, ∧, ∨

    • Mape Apply: /@, //@. @@,@@@

  4. Prefisso e notazione infisso:

    • Print@"hello" al posto di Print["hello"]

    • a~f~b al posto di f[a,b]

  5. Quando una funzione viene utilizzata una sola volta, una funzione pura può economizzare un carattere o due.

  6. Unire le stringhe in un elenco. ""<>{"a","b","c"}invece diStringJoin@{"a","b","c"}

  7. Sfrutta le funzioni elencabili. Più lunghe sono le liste, meglio è.

    {a, b, c} + {x, y, z}= {a+x, b+y, c+z}

    {2, 3, 4} {5, 6, 7}= {10, 18, 28}

    {{a, b}, {c, d}}^{2, 3} = {{a^2, b^2}, {c^3, d^3}}


2
È sempre più breve scrivere (Norm[#-#2]&)invece di EuclideanDistance.
user202729,

32

Alcune funzioni integrate con nomi lunghi possono essere sostituite con espressioni più brevi.

Per esempio:

  • Total => Tr
  • Transpose=> Threado\[Transpose]
  • True => 1<2
  • False => 1>2
  • Times => 1##&
  • Alternatives => $|##&
  • IntegerQ => ⌊#⌋==#&
  • a[[1]] => #&@@a
  • a[[All,1]] => #&@@@a
  • ConstantArray[a,n]=> Array[a&,n]oTable[a,{n}]
  • Union@a=> {}⋃aoa⋃a
  • ToExpression@n=> FromDigits@nif nè un numero
  • Divisible[n,m] => m∣n
  • FromDigits[n,2]=> Fold[#+##&,n]Se nè un elenco di 0s e 1s
  • Complex@z=> {1,I}.zdove zè un elenco del modulo{x,y}

5
@belisarius Thread[{{a,b},{c,d}}]== Thread[List[{a,b},{c,d}]]== {List[a,c],List[b,d]}== {{a,c},{b,d}}==Transpose[{{a,b},{c,d}}]
alephalpha

2
Penso che il tuo Foldtrucco per FromDigitsfunziona anche per qualsiasi altra base tranne 10. Ad esempio FromDigits[n,5]-> Fold[4#+##&,n](con il vantaggio di salvare un byte extra per basi 100e 1000).
Martin Ender,

1
@ mbomb007 3 byte in UTF-8. In realtà questo personaggio lo è U+F3C7.
alephalpha,

1
Alla fine ho installato 10.3. Se stiamo prendendo in considerazione programmi completi, non credo Echosia un'opzione, perché stampa >>(e uno spazio) su STDOUT prima di stampare la stringa effettiva.
Martin Ender,

2
Perché Complex[x,y] => {1,I}.{x,y}, penso che x+y*Isia molto più breve con lo stesso effetto?
Shieru Asakoto,

22

Elenchi con valori ripetuti

Questo è un vettore abbastanza comune con cui lavorare:

{0,0}

Si scopre che questo può essere ridotto di un byte:

0{,}

Vengono salvati anche più byte se il vettore è più lungo di due zeri. Questo può anche essere usato per inizializzare zero matrici, ad esempio il seguente fornisce una matrice 2x2 di zeri:

0{{,},{,}}

Questo può essere utilizzato anche per valori diversi da zero se sono sufficientemente grandi o sufficientemente numerosi o negativi. Confronta le seguenti coppie:

{100,100}
0{,}+100
{-1,-1}
0{,}-1
{3,3,3,3}
0{,,,}+3

Ma ricorda che a partire da 6 valori, ti conviene 1~Table~6in questo caso (potenzialmente prima, a seconda dei requisiti di precedenza).

Il motivo per cui funziona è che ,introduce due argomenti nell'elenco, ma gli argomenti omessi (ovunque in Mathematica) sono impliciti Null. Inoltre, la moltiplicazione è Listableed 0*xè 0per quasi tutti x(tranne per cose come Infinitye Indeterminate), quindi ecco cosa sta succedendo:

  0{,}
= 0*{,}
= 0*{Null,Null}
= {0*Null,0*Null}
= {0,0}

Per gli elenchi di 1s, puoi usare un trucco simile usando le regole di esponenziazione. Esistono due modi diversi per salvare i byte se 1nell'elenco sono presenti almeno tre secondi:

{1,1,1}
1^{,,}
{,,}^0

7
+1; questo dimostra che Mathematica può essere integrata per tutto, ma giocare a golf può essere una vera sfida.
LegionMammal978,

Se si desidera un array che alla fine viene riempito con 1s, allora 1^{,,,}è un byte più piccolo di 0{,,,}+1.
Misha Lavrov,

@MishaLavrov Oh, buona cattura. Ciò lo rende più breve a tre valori e puoi anche usarlo {,,}^0. Modifica il post.
Martin Ender,

19

Conosci i tuoi argomenti di pura funzione

Quando giochi a golf, utilizzerai spesso un approccio funzionale, in cui usi funzioni anonime (pure) con la &sintassi abbreviata. Esistono molti modi diversi per accedere agli argomenti di tale funzione e spesso puoi radere un paio di byte avendo una buona conoscenza delle possibilità.

Accesso a singoli argomenti

Probabilmente lo sai se hai già usato funzioni pure. Il n ° argomento è indicato come #n, e #agisce come un alias per #1. Quindi, se, per esempio, vuoi scrivere una funzione che accetta come parametri un'altra funzione e il suo argomento (per passare l'argomento a quella funzione), usa

#@#2&

Questo non funziona con numeri negativi (come potresti usare quando accedi agli elenchi).

Accesso agli argomenti denominati (novità in V10)

Una delle principali nuove funzionalità del linguaggio in Mathematica 10 è Associations, che sono fondamentalmente mappe di valori-chiave con tipi di chiavi arbitrari, scritte come

<| x -> 1, "abc" -> 2, 5 -> 3 |>

Se tale associazione viene passata come primo argomento a una funzione pura, è possibile accedervi se i suoi argomenti sono denominati parametri:

{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)

Si noti che #fa ancora riferimento all'intera associazione come previsto. Perché i parametri nominati funzionino, le chiavi devono essere stringhe (non funzionerà se ad esempio si utilizzano variabili non definite) e tali stringhe devono iniziare con una lettera e contenere solo lettere e cifre.

L'argomento "auto" #0

#0Esiste anche una caratteristica meno conosciuta , che fornisce l'oggetto funzione stesso. Questo può essere davvero utile in quines e quines generalizzate. In effetti, il quine Mathematica più corto (lo so) è

ToString[#0][] & []

La cosa leggermente fastidiosa è che non ti darà i caratteri esatti che hai inserito. Ad esempio, se utilizzato @per l'applicazione della funzione, verrà comunque visualizzato come [...]e gli spazi verranno inseriti in alcuni punti. Questo di solito renderà il quine un po 'più lungo di quanto vorresti che fosse, ma funzionerà sempre, giocando prima sul golf e poi copiandone l'output, che ora dovrebbe essere un vero quin.

Oltre alle quines, questo significa anche che puoi scrivere codice ricorsivo senza dover nominare la tua funzione. Confronta queste tre implementazioni di Fibonacci (ingenue ma giocate a golf):

f@0=0;f@1=1;f@n_:=f[n-1]+f[n-2]
f@n_:=If[n<2,n,f[n-1]+f[n-2]]
If[#<2,#,#0[#-1]+#0[#-2]]&

Sequenze di argomenti

Ora è qui che inizia la vera magia. Le sequenze non vengono utilizzate spesso nel golf, perché Sequenceè un nome troppo lungo per valerne la pena il più delle volte. Ma nelle funzioni pure è dove brillano. Se non hai familiarità con le sequenze, sono fondamentalmente come simboli in alcune altre lingue, se usi una sequenza in una Listo nella lista degli argomenti di una funzione, i suoi elementi verranno automaticamente espansi in slot separati. Così

{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]

Ora, in pure funzioni ##o ##1è una sequenza di tutti gli argomenti. Allo stesso modo, ##2è una sequenza di tutti gli argomenti a partire dal secondo, ##3tutti gli argomenti a partire dal terzo ecc. Quindi, per cominciare, possiamo semplicemente reimplementarli Sequencecome ##&, salvando 5 byte. Come esempio di utilizzo, questo ci fornisce un'alternativa a Join@@list(vedi questo suggerimento ), che non salva alcun byte, ma è bene sapere comunque:

 ##&@@@list

Ciò appiattisce efficacemente il primo livello di un elenco nidificato. Cos'altro possiamo fare con questo? Ecco un'alternativa più breve di 2 byte a RotateLeft:

 RotateLeft@list
 {##2,#}&@list

Solo per queste cose vale la pena tenere presente questa funzionalità. Tuttavia, possiamo fare di meglio! Le sequenze diventano davvero interessanti se si considera che gli operatori sono effettivamente implementati come funzioni sotto il cofano. Ad esempio, in a+brealtà valuta Plus[a,b]. Quindi se diamo una sequenza ...

1+##&[1,2,3]
=> Plus[1,##] 
=> Plus[1,1,2,3]
=> 7

Questo trucco è stato utilizzato in questo suggerimento per salvare un byte Times, poiché la giustapposizione è tecnicamente anche solo un operatore:

1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6

Puoi anche usarlo per salvare un byte Unequalse hai un valore a singolo carattere o una variabile che sai non è nei tuoi argomenti ( Nprobabilmente funzionerà nel 99% dei casi):

Unequal[a,b,c]
N!=##&[a,b,c]

Ciò diventa ancora più interessante con gli operatori unari -e /- gli ultimi due sono effettivamente implementati in termini di moltiplicazione ed esponenziazione. Ecco un elenco di cose che puoi fare, in cui l'ultima colonna presuppone che gli argomenti siano stati passati alla funzione a, b, c:

Operator    Function                Expanded                    Equivalent to

+##         Plus[##]                Plus[a,b,c]                 a+b+c
1##         Times[1,##]             Times[1,a,b,c]              a*b*c
-##         Times[-1,##]            Times[-1,a,b,c]             -a*b*c
x+##        Plus[x,##]              Plus[x,a,b,c]               x+a+b+c
x-##        Plus[x,Times[-1,##]]    Plus[x,Times[-1,a,b,c]]     x-a*b*c
x##         Times[x,##]             Times[x,a,b,c]              x*a*b*c
x/##        Times[x,Power[##,-1]]   Times[x,Power[a,b,c,-1]]    x*a^b^c^-1
##/x        Times[##,Power[x,-1]]   Times[a,b,c,Power[x,-1]]    a*b*c/x
x^##        Power[x,##]             Power[x,a,b,c]              x^a^b^c
##^x        Power[##,x]             Power[a,b,c,#]              a^b^c^x
x.##        Dot[x,##]               Dot[x,a,b,c]                x.a.b.c

Altri operatori sono comuni !=, ==, &&, ||. Quelli meno comuni da tenere a mente sono |, @*, /*. Per concludere, ecco un piccolo trucco bonus:

####        Times[##,##]            Times[a,b,c,a,b,c]          (a*b*c)^2

Continua a sperimentare con questi e fammi sapere se trovi altre applicazioni utili o particolarmente interessanti!


15

Sqrt@2o 2^.5=>√2

a[[1]]=>a〚1〛

#+#2&=>+##&

Flatten@a=> Join@@a(a volte)

Function[x,x^2]=> xx^2o#^2&

a〚1;;-1;;2〛=>a〚;;;;2〛

a〚2;;-1 ;;2〛=>a〚2;;;;2〛

a〚All,1〛=>a〚;;,1〛

{{1}}〚1,1〛=>Tr@{{1}}

0&~Array~10=>0Range@10

Range[10^3]=>Range@1*^3


1
Si noti che quando si misura per byte, utilizzando e richiede 3 byte ciascuno (si supponga UTF8)
user202729,

12

Operatori come funzioni

Ispirato dalla recente scoperta di Dennis per Julia, ho pensato di analizzarlo per Mathematica. Ero consapevole che Mathematica definisce un gran numero di operatori inutilizzati, ma non ci ho mai prestato molta attenzione.

Per riferimento, l'elenco di tutti gli operatori può essere trovato qui sotto forma di una tabella di precedenza. Il triangolo nell'ultima colonna indica se quell'operatore ha un significato incorporato o meno. Anche se non tutti quelli che non possono essere definiti facilmente, la maggior parte può farlo.

Convenientemente, ci sono due operatori inutilizzati con un punto di codice inferiore a 256, in modo che possano essere utilizzati come singoli byte in un file di origine codificato ISO 8859-1:

  • ± (0xB1) può essere utilizzato come operatore prefisso unario o operatore binario infix.
  • · (0xB7) può essere utilizzato come operatore variadic o n-ary infix, per n> 2.

C'è ancora un altro problema: per qualche strana ragione quando si definiscono questi operatori è necessario uno spazio davanti a loro, altrimenti Mathematica cerca di analizzare una moltiplicazione. Quando li usi non hai bisogno di spazi:

±x_:=2x
x_ ±y_:=x+y
x_ ·y_ ·z_:=x*y+z
Print[±5]  (* 10 *)
Print[3±4] (*  7 *)
Print[3·4·5] (* 17 *)

Confronta questo con:

f@x_:=2x
x_~g~y_:=x+y
h[x_,y_,z_]:=x*y+z
Print[f@5]   (* 10 *)
Print[3~g~4] (*  7 *)
Print[h[x,y,z]] (* 17 *)

In questo modo si salva un byte quando si definisce la funzione e due byte quando si utilizza. Si noti che la definizione di ·non salverà byte per quattro operandi e inizierà a costare byte per più operandi, ma l'utilizzo potrebbe comunque salvare byte, a seconda della precedenza degli operatori utilizzati negli argomenti. È anche utile notare che è possibile definire in modo economico una funzione variadica che può quindi essere chiamata in modo molto più efficiente:

x_ ·y__:={y}
Print[1·2·3·4·5] (* {2, 3, 4, 5} *)

Ma nota che non è facile chiamare queste funzioni variadiche con un solo argomento. (Potresti farlo CenterDot[x]o, ##&[]·xma se hai davvero bisogno che ci siano buone possibilità, stai meglio con una soluzione diversa.)

Naturalmente, questo non sta salvando nulla per soluzioni in cui è sufficiente una funzione senza nome, ma a volte è necessario definire le funzioni di supporto da utilizzare in seguito, e talvolta è più breve definire funzioni con nome, ad esempio per impostare definizioni diverse per parametri diversi. In questi casi, l'utilizzo di un operatore può salvare una discreta quantità di byte.

Si noti che l'utilizzo di questi file con codifica ISO 8859-1 richiede $CharacterEncodingdi essere impostato su un valore compatibile, come quello predefinito di Windows WindowsANSI. In alcuni sistemi, per impostazione predefinita UTF-8, non sarà in grado di leggere questi punti di codice da singoli byte.


Questo è davvero fantastico, non sapevo che Mathematica avesse un elenco di operatori e ne includevo persino la precedenza. Quei due operatori che hai trovato sono sicuro che ti torneranno utili.
miglia,

8

Scelta dei valori in base al numero intero

L'approccio ingenuo tra cui scegliere ye z, a seconda che xsia 0o 1è

If[x<1,y,z]

Tuttavia, c'è un modo più breve:

y[z][[x]]

Questo funziona perché [[0]]dà la Headdi un'espressione, in questo caso y, mentre [[1]]solo dà il primo elemento - in questo caso il primo argomento, z.

Puoi anche usarlo per scegliere tra più di due valori:

u[v,w][[x]]

Nota che questo non funzionerà se uè una funzione che valuta effettivamente qualcosa. È importante che Mathematica si mantenga u[v,w]così com'è. Tuttavia, questo funziona nella maggior parte dei casi, incluso if uis a è un numero, una stringa o un elenco.

I crediti per questo trucco vanno ad alephalpha - l'ho scoperto in una delle sue risposte.

Se xè basato su 1 anziché su zero, basta usare

{y,z}[[x]]

o

{u,v,w}[[x]]

In alcuni rari casi, puoi persino sfruttare il fatto che la moltiplicazione non viene valutata per alcuni valori:

{"abc","def"}[[x]]
("abc""def")[[x]]

Nota però che Mathematica riordinerà effettivamente gli argomenti, di una moltiplicazione se rimane non valutata, quindi quanto sopra è identico a

("def""abc")[[x]]

8

Alternative a Length

Questo è stato interamente riscritto con alcuni suggerimenti di LegionMammal978 e Misha Lavrov. Mille grazie a entrambi.

In molti casi, Lengthpuò essere abbreviato un po 'usando Tr. L'idea di base è trasformare l'input in un elenco di 1s, in modo che Trli sommi che equivale quindi alla lunghezza dell'elenco.

Il modo più comune per farlo è usare 1^x(per un elenco x). Questo funziona perché Powerè Listablee 1^nper la maggior parte dei valori atomici nè giusto 1(compresi tutti i numeri, stringhe e simboli). Quindi possiamo già salvare un byte con questo:

Length@x
Tr[1^x]

Naturalmente, ciò presuppone che si xtratti di un'espressione con una precedenza superiore a ^.

Se xcontiene solo 0s e 1s, possiamo salvare un altro byte usando Factorial(supponendo che xabbia una precedenza maggiore di !):

Length@x
Tr[x!]

In alcuni rari casi, xpotrebbe avere una precedenza inferiore rispetto a quella ^ancora maggiore rispetto alla moltiplicazione. In tal caso, avrà anche una precedenza inferiore rispetto a @, quindi dobbiamo davvero confrontarci Length[x]. Un esempio di tale operatore è .. In questi casi, puoi comunque salvare un byte con questo modulo:

Length[x.y]
Tr[0x.y+1]

Infine, alcune osservazioni sul tipo di elenchi su cui funziona:

Come accennato in alto, funziona su elenchi piatti contenenti solo numeri, stringhe e simboli. Tuttavia, funzionerà anche su alcuni elenchi più profondi, anche se in realtà calcola qualcosa di leggermente diverso. Per un array rettangolare n -D, l'utilizzo Trfornisce la dimensione più breve (al contrario della prima). Se sai che la dimensione più esterna è la più breve, o sai che sono tutte uguali, le Trespressioni -e sono ancora equivalenti Length.


3
Appena trovato una soluzione ancora più breve: Length@x == Tr[1^x]. Dovrebbe funzionare con la maggior parte degli elenchi.
LegionMammal978,

@ LegionMammal978 è fantastico, grazie :). Lo modificherò presto.
Martin Ender,

1
Due volte, mi sono trovato a utilizzare Tr[x!]invece di Tr[1^x]salvare un byte nel caso speciale in cui xcontiene solo zero e uno.
Misha Lavrov,

@MishaLavrov È davvero pulito! :)
Martin Ender,

7
  1. Esplora soluzioni ricorsive : Mathematica è multi-paradigma, ma l'approccio funzionale è spesso il più economico. NestWhilepuò essere una soluzione molto compatta ai problemi di ricerca NestWhileListe FoldListsono potenti quando è necessario restituire o elaborare i risultati di iterazioni intermedie. Map (/@), Apply (@@, @@@), MapThread, E davvero tutto su di Wolfram programmazione funzionale pagina di documentazione è roba potente.

  2. Modulo abbreviato per incremento / decremento - Ad esempio, invece di While[i<1,*code*;i++]te puoi farlo
    While[i++<1,*code*]

  3. Non dimenticare che puoi pre-incrementare / decrementare , ad esempio --iinvece di i--. Questo a volte può farti risparmiare qualche byte nel codice circostante eliminando un'operazione preparatoria.

  4. Corollario del n. 5 di David Carraher: quando la stessa funzione viene utilizzata più volte, assegnando un simbolo ad essa può salvare byte. Ad esempio, se si utilizza ToExpression4 volte in una soluzione, è t=ToExpressionpossibile utilizzarlo t@*expression*successivamente. Tuttavia, prima di procedere, considerare se l'applicazione ripetuta della stessa funzione indica un'opportunità per un approccio ricorsivo più economico.


MapThreadpuò essere spesso sostituito da \[Transpose]. TIO .
user202729

7

Non usare {}se stai usando @@@.

In alcuni casi, potresti incontrare un'espressione come:

f@@@{{a,b},{c,d}}

È possibile ridurre i byte scrivendo:

f@@@{a|b,c|d}

Alternativesha una precedenza molto bassa, quindi in genere va bene scrivere espressioni (un'eccezione notevole sono le funzioni pure; puoi usarla solo nell'elemento più a sinistra di Alternatives).

f@@@{f@a|b~g~1,#^2&@c|d@2}

Nota che f@@a|b|c(invece di f@@{a,b,c}) non funziona perché Applyha una precedenza superiore a Alternative.

In questo caso, dovresti semplicemente usare f@@{a,b,c}.


6

Solo Mathematica 10

Moduli operatore

Mathematica 10 supporta i cosiddetti "moduli operatore", il che significa sostanzialmente che alcune funzioni possono essere modificate. La promozione di una funzione è quella di creare una nuova funzione fissando uno dei suoi operatori. Supponiamo che tu stia utilizzando SortBy[list, somereallylongfunction&]molte lists diverse . Prima, probabilmente sarebbe stato assegnato SortByal se la pura funzione di fcosì

s=SortBy;
f=somereallylongfunction&;
list1~s~f;
list2~s~f;
list3~s~f;

Ora puoi curry SortBy, il che significa che ora puoi farlo

s=SortBy[somereallylongfunction&];
s@list1;
s@list2;
s@list3;

Le stesse opere per un sacco di altre funzioni, che assumono un elenco o una funzione argomenti, tra cui (ma non solo) Select, Map, Nearest, etc.

ybeltukov su Mathematica.SE è stato in grado di produrre un elenco completo di questi :

{"AllTrue", "AnyTrue", "Append", "Apply", "AssociationMap", "Cases", 
 "Count", "CountDistinctBy", "CountsBy", "Delete", "DeleteCases", 
 "DeleteDuplicatesBy", "Extract", "FirstCase", "FirstPosition", 
 "FreeQ", "GroupBy", "Insert", "KeyDrop", "KeyExistsQ", "KeyMap", 
 "KeySelect", "KeySortBy", "KeyTake", "Map", "MapAt", "MapIndexed", 
 "MatchQ", "MaximalBy", "MemberQ", "Merge", "MinimalBy", "NoneTrue", 
 "Position", "Prepend", "Replace", "ReplacePart", "Scan", "Select", 
 "SelectFirst", "SortBy", "StringCases"}

Composizione e composizione giusta

Ci sono nuove scorciatoie per Composition( @*) e RightComposition( /*). Un esempio evidentemente inventato in cui questi possono salvare personaggi è visto nelle seguenti tre linee equivalenti

Last@Range@# & /@ Range[5]
Last@*Range /@ Range[5]
Range /* Last /@ Range[5]

5

Non scrivere funzioni con argomento 0

Non è necessario un codice come questo:

f[]:=DoSomething[1,2]
(*...*)
f[]
(*...*)
f[]

Puoi semplicemente usare una variabile con :=per forzare la rivalutazione del lato destro:

f:=DoSomething[1,2]
(*...*)
f
(*...*)
f

Ciò significa anche che puoi alias qualsiasi azione che esegui spesso (anche se è qualcosa di simile n++) a un singolo personaggio al costo di 5 byte. Quindi nel caso in n++cui ripaghi dopo il quarto utilizzo:

n++;n++;n++;n++
f:=n++;f;f;f;f

5

Utilizzare %per ottenere una variabile gratuita

Questo suggerimento è applicabile solo se si può presumere l'ambiente REPL di Mathematica. %non è definito quando il codice viene eseguito come script.

Quando è possibile utilizzare le funzionalità REPL, non procedere come segue:

a=someLongExpression;some[other*a,expression@a,using^a]

Invece, ricorda che Mathematica memorizza l'ultima espressione valutata (terminata da nuova riga) in %:

someLongExpression;
some[other*%,expression@%,using^%]

La nuova riga aggiunta costa un byte, ma ne stai risparmiando due rimuovendola a=, quindi nel complesso questo risparmia un byte.

In alcuni casi (ad es. Quando si desidera stampare acomunque il valore ), è anche possibile interrompere il ;salvataggio di due byte:

someLongExpression
some[other*%,expression@%,using^%]

Uno o due byte possono sembrare abbastanza minori, ma questo è un caso importante, perché rende l'estrazione di espressioni ripetute (che è una tecnica molto comune) molto più utile quando si gioca a golf:

La normale tecnica di estrazione di espressioni ripetute costa quattro byte di overhead, che devono essere salvati con ulteriori usi dell'espressione. Ecco una breve tabella del numero minimo di usi di un'espressione (per lunghezza dell'espressione) per l'estrazione in una variabile denominata per salvare qualsiasi cosa:

Length   Min. Uses
2        6
3        4
4        3
5        3
6        2
...      2

Utilizzando la variabile senza nome, sarà possibile salvare un paio di byte molto più spesso:

When ; is required                        When ; can be omitted

Length   Min. Uses                        Length   Min. Uses
2        5                                2        4
3        3                                3        3
4        3                                4        2
5        2                                ...      2
...      2

Non credo %%o %npossa essere usato per giocare a golf, perché se non li usi almeno due volte, puoi semplicemente posizionare l'espressione dove serve. E se lo usi due volte, il carattere aggiuntivo nel nome della variabile annulla i risparmi derivanti dall'omissione di alcuni x=.


Si noti che non funziona in modalità script.
alephalpha,

@alephalpha Che cos'è la modalità script?
Martin Ender,


@alephalpha Oh, giusto, ho chiuso il cervello lì per un secondo ... quindi ciò significherebbe che non può essere realmente utilizzato, a meno che non si possa ipotizzare l'ambiente REPL.
Martin Ender,

5

Verifica se un elenco è ordinato

Questo è essenzialmente un corollario di questo suggerimento, ma questo è un compito sufficientemente comune che penso che meriti la propria risposta.

Il modo ingenuo per verificare se un elenco è in ordine è quello di utilizzare

OrderedQ@a

Possiamo fare un byte meglio con

Sort@a==a

Tuttavia, questo non funziona se non abbiamo già ciò che vogliamo controllare in una variabile. (Avremmo bisogno di qualcosa di simile Sort[a=...]==ache è inutilmente lungo.) Tuttavia, c'è un'altra opzione:

#<=##&@@a

La cosa migliore è che questo può essere usato per verificare se l'ingresso è in ordine inverso per lo stesso conteggio byte:

#>=##&@@a

È possibile salvare un altro byte se a) sappiamo che gli elementi dell'elenco sono distinti eb) conosciamo un limite inferiore compreso tra 0 e 9 (compreso; o limite superiore per l'ordine ordinato inverso):

0<##&@@a
5>##&@@a

Per capire perché funziona, dai un'occhiata a "Sequenze di argomenti" nel suggerimento collegato in alto.


In alternativa, (stretta) in basso a diretto a reverse-ordinato anche il lavoro: ##>0&@@a. Simile per limite superiore per ordinato.
user202729

@ user202729 Oh buon punto, sentiti libero di modificare (altrimenti cercherò di farlo nel fine settimana se ricordo).
Martin Ender,

5

Ripetendo una stringa

Invece di StringRepeat[str,n]usare (0Range[n]+str)<>"". O se strnon dipende da alcun argomento relativo allo slot, è ancora meglio Array[str&,n]<>""seguire questo suggerimento.


1
Corollario: invece di StringRepeat[s,n+1]usare Array[s&,n]<>s(anche quando hai già n+1una variabile).
Martin Ender,

Meglio,Table[str,n]<>""
attinat il

5

Se hai bisogno di un elenco di numeri ordinati al contrario, non utilizzare

Reverse@Sort@x

ma

-Sort@-x

per salvare sei byte. L'ordinamento per valore negativo è utile anche per gli SortByscenari:

Reverse@SortBy[x,Last]
SortBy[x,-Last@#&]

2
Che dire -Sort@-x?
JungHwan Min

1
@JungHwanMin Oh, uhhh, sì, va molto meglio. :)
Martin Ender l'

4

È possibile inserire un'espressione in Breakcui è possibile salvare uno o due caratteri. Esempio ( altri dettagli non chiariti per chiarezza ):

result = False;
Break[]

può essere trasformato in

Break[result = False]

per salvare un personaggio. Se l'espressione in questione non ha una precedenza inferiore rispetto all'applicazione della funzione, puoi anche salvare un altro carattere:

Print@x;
Break[]

può essere trasformato in

Break@Print@x

Anche se non documentato, l'argomento Breaksembra essere restituito dal circuito circostante, il che può potenzialmente portare a ulteriori risparmi.


4

Per rimuovere tutti gli spazi bianchi da una stringa s, utilizzare

StringSplit@s<>""

Cioè, usa StringSplitil valore predefinito (diviso in componenti non bianchi) e semplicemente ricollegali. Lo stesso è probabilmente il più breve se vuoi sbarazzarti di qualsiasi altro personaggio o sottostringa:

s~StringSplit~"x"<>""

4

Alternative a Range

Un compito molto comune è applicare una sorta di funzione a tutti i numeri da 1 a a n(di solito forniti come input). Esistono essenzialmente 3 modi per farlo (usando come esempio una funzione di identità senza nome):

#&/@Range@n
Array[#&,n]
Table[i,{i,n}]

Tendo ad andare per il primo (per qualsiasi motivo), ma questa è raramente la scelta migliore.

Usando Arrayinvece

L'esempio sopra mostra che l'utilizzo Arrayha lo stesso numero di byte. Tuttavia, ha il vantaggio di essere una singola espressione. In particolare, se si desidera elaborare ulteriormente il risultato con una funzione, fè possibile utilizzare la notazione con prefisso, che consente di salvare un byte su Range:

f[#&/@Range@n]
f@Array[#&,n]

Inoltre, potresti essere in grado di omettere le parentesi attorno alla tua funzione senza nome di cui potresti aver bisogno Range, ad es

15/(#&)/@Range@n
15/Array[#&,n]

Se non vuoi usarlo ulteriormente (o con un operatore che ha una precedenza minore), puoi invece scrivere Arrayse stesso in notazione infissa e anche salvare un byte:

#&/@Range@n
#&~Array~n

Quindi, Arrayè quasi certamente meglio diRange .

utilizzando Tableinvece

Ora la tabella deve recuperare 3 byte, o almeno 2 quando la notazione infissa è un'opzione:

#&/@Range@n
i~Table~{i,n}

Quando non si utilizza la notazione infissa, è Tablepossibile omettere le parentesi se la funzione è composta da più istruzioni:

(#;#)&/@Range@n
Table[i;i,{i,n}]

Questo è ancora più lungo, ma offre ulteriori risparmi nel caso indicato di seguito.

I risparmi reali derivano dal fatto che Tabledà un nome alla variabile corrente non deve essere respinto. Spesso, avrai annidato funzioni senza nome in cui desideri utilizzare la variabile esterna all'interno di una delle funzioni interne. Quando ciò accade, Tableè più breve di Range:

(i=#;i&[])&/@Range@n
Table[i&[],{i,n}]
i&[]~Table~{i,n}

Non solo si salvano i caratteri per l'assegnazione i, ma si potrebbe anche essere in grado di ridurre la funzione a una singola istruzione nel processo, che consente di utilizzare la notazione infix su di essa. Per riferimento, Arrayè anche più lungo in questo caso, ma comunque più corto di Range:

(i=#;i&[])&~Array~n

Quando useresti effettivamente Range ?

Ogni volta che non è necessaria una chiamata di funzione per elaborare i valori, ad esempio quando la mappatura può essere eseguita tramite un'operazione vettoriale. Per esempio:

5#&~Array~n
5Range@n
#^2&~Array~n
Range@n^2

Naturalmente, è anche più breve se non si desidera mappare alcuna funzione, ad es

Mean@Array[#&,n]
Mean@Range@n

Finalmente qualcun altro che usa f/@Range[x]regolarmente ...
LegionMammal978,

4

Trovare il numero più piccolo che soddisfa una condizione

Qualche costrutto come i=1;While[cond[i],i++]va bene così com'è, ma esiste un'alternativa che è più corta di due byte:

1//.i_/;cond[i]:>i+1

Il codice precedente sostituisce ripetutamente un numero icon i+1mentre soddisfa la condizione cond[i]. In questo caso, iinizia alle 1.

Si noti che il numero massimo predefinito di iterazioni è 2 ^ 16 (= 65536). Se hai bisogno di più iterazioni di così, Whilesarebbe meglio. ( MaxIterations->∞è troppo lungo)


4

Abuso della valutazione del corto circuito

A volte è possibile sostituire Ifcon un operatore logico.

Ad esempio, supponiamo che tu voglia creare una funzione che controlli se un numero è primo e stampa 2*(number) - 1se è vero:

If[PrimeQ@#,Print[2#-1]]&

È più breve se si utilizza &&invece:

PrimeQ@#&&Print[2#-1]&

Anche quando hai più espressioni, risparmi ancora byte:

If[PrimeQ@#,a++;Print[2#-1]]&

PrimeQ@#&&a++&&Print[2#-1]&
(* or *)
PrimeQ@#&&(a++;Print[2#-1])&

È possibile utilizzare ||per i casi in cui si desidera che la condizione sia False:

If[!PrimeQ@#,Print[2#-1]]&
(* or *)
If[PrimeQ@#,,Print[2#-1]]&
(* can become *)
PrimeQ@#||Print[2#-1]&

Questi trucchi funzionano perché gli operatori logici possono essere cortocircuitati ; il secondo argomento e, successivamente, non devono neppure essere espressioni booleane valide.

Naturalmente, questo non funziona se hai bisogno del valore di ritorno di Ifo quando hai bisogno di argomenti sia sinceri che falsi If.



3

utilizzando Optional (:)

Optional (:) può essere utilizzato per espandere gli elenchi nelle sostituzioni, senza dover definire una regola separata per l'espansione.

Questa mia risposta e questa risposta di @ngenisis sono esempi.

uso

... /. {p___, a_: 0, b_, q___} /; cond[b] :> ...

La sostituzione precedente utilizza prima il modello {p___, a_, b_, q___}e trova una corrispondenza taleb soddisfare una determinata condizione.

Quando tale corrispondenza non viene trovata, omette a_e invece cerca {p___, b_, q___}. anon è incluso nella ricerca e si presume che abbia il valore 0.

Si noti che la seconda ricerca del modello funzionerebbe solo per bciò che si verifica all'inizio dell'elenco; se un bvalore che soddisfa una condizione è nel mezzo, allora {p___, a_, b_, q___}(che ha una precedenza più elevata) corrisponderebbe invece a esso.

La sostituzione equivale a anteporre a 0quando si bverifica una condizione soddisfacente all'inizio dell'elenco. (ovvero non è necessario definire una regola separata {b_, q___} /; cond[b] :> ...)


3

Sapere quando (e quando no) utilizzare argomenti con funzioni pure denominate

Per il golf del codice, gli Functionargomenti puri sono più comunemente referenziati usando Slots; ad es. #per il primo argomento, #2per il secondo, ecc. (vedere questa risposta per maggiori dettagli).

In molti casi, vorrai nidificare Functions. Ad esempio, 1##&@@#&è un oggetto Functionche prende una lista come primo argomento e produce il prodotto dei suoi elementi. Ecco quella funzione in TreeForm:

inserisci qui la descrizione dell'immagine

Argomenti passati al livello superiore Functionpuò solo riempimento Slots e SlotSequencepresenti a livello superiore, che in questo caso significa che il s SlotSequencenel interno Functionnon avrà alcun modo di accedere argomenti al livello superiore Function.

In alcuni casi, tuttavia, potresti volere un Functionnidificato all'interno di un altro Functionper poter fare riferimento agli argomenti all'esterno Function. Ad esempio, potresti voler qualcosa di simile Array[fun,...]&, in cui la funzione fundipende da un argomento al livello più alto Function. Per concretezza, diciamo che fundovrebbe dare al resto del quadrato del suo modulo di input l'input al livello più alto Function. Un modo per ottenere ciò è quello di assegnare l'argomento di livello superiore a una variabile:

(x=#;Array[Mod[#^2,x]&,...])&

Ovunque xappaia all'interno Function Mod[#^2,x]&, farà riferimento al primo argomento all'esterno Function, mentre #farà riferimento al primo argomento all'interno Function. Un approccio migliore consiste nell'utilizzare il fatto che Functionha una forma a due argomenti in cui il primo argomento è un simbolo o un elenco di simboli che rappresenteranno argomenti denominati per Function(al contrario di Slots senza nome ). Questo finisce per salvarci tre byte in questo caso:

xArray[Mod[#^2,x]&,...]

è il carattere di uso privato a tre byte che U+F4A1rappresenta l'operatore binario infix \[Function]. Puoi anche usare la forma binaria di Functionun altro Function:

Array[xMod[x^2,#],...]&

Ciò equivale a quanto sopra. La ragione è che, se si sta utilizzando gli argomenti predefiniti, quindi Slots e SlotSequencessi presume che appartenere alla successiva Functiondi sopra del quale non usa argomenti denominati.

Ora, solo perché possiamo nidificare Functionin questo modo, non significa che dovremmo sempre. Ad esempio, se volessimo selezionare quegli elementi di un elenco che sono inferiori all'input, potremmo essere tentati di fare qualcosa del tipo:

Select[...,xx<#]&

In realtà sarebbe più breve da usare Casesed eviterebbe la necessità di un nidificato del Functiontutto:

Cases[...,x_/;x<#]&

2

È possibile salvare un byte aggirando Prependo PrependTo:

l~Prepend~x
{x}~Join~l
{x,##}&@@l

o

l~PrependTo~x
l={x}~Join~l
l={x,##}&@@l

Sfortunatamente, questo non aiuta per i più comuni Append, che sembra essere l'equivalente più breve di un Array.push()in altre lingue.


2

Mathematica 10.2: BlockMapè Partition+Map

Questo suggerimento potrebbe anche essere intitolato "Leggi le note di rilascio, tutte". (Per riferimento, ecco le note di rilascio per la 10.2 e qui la versione 10.3 di oggi .)

Ad ogni modo, anche le versioni minori contengono molte nuove funzionalità e una delle più utili (per il golf) della versione 10.2 è la nuova BlockMapfunzione. Combina essenzialmente Partitione Map, il che è ottimo per i golfisti, perché Partitionviene usato abbastanza spesso, ed è un nome di funzione davvero fastidiosamente lungo. La nuova funzione non si accorcia Partitionda sola, ma ogni volta che si desidera mappare una funzione sulle partizioni (che probabilmente accade più spesso), ora è possibile salvare un byte o due:

#&/@l~Partition~2
BlockMap[#&,l,2]
#&/@Partition[l,3,1]
BlockMap[#&,l,3,1]

I risparmi aumentano ulteriormente quando la nuova posizione della funzione senza nome consente di salvare alcune parentesi:

#&@@(#&/@Partition[l,3,1])
#&@@BlockMap[#&,l,3,1]

Sfortunatamente, non ho idea del perché non abbiano aggiunto anche BlockApplymentre erano lì ...

Si noti inoltre che BlockMapnon supporta il quarto parametro che è possibile utilizzare Partitionper ottenere un elenco ciclico:

Partition[Range@5, 2, 1, 1]
(* Gives {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 1}} *)
BlockMap[f, Range@5, 2, 1, 1]
(* Nope... *)

2

Memorizzazione di funzioni ed espressioni in una variabile

Se la tua risposta finisce per usare più volte le stesse funzioni o espressioni, potresti prendere in considerazione l'idea di memorizzarle in variabili.

Se la tua espressione è lunghezza le la usi nvolte, normalmente userebbe i l * nbyte.

Tuttavia, se lo memorizzi in una variabile di lunghezza 1, occorrerebbero solo 3 + l + nbyte (o 2 + l + nbyte, se assegni la variabile a cui non ti serviranno CompoundExpression (;)o tra parentesi).


Ad esempio, consideriamo un problema semplice, trovando numeri primi gemelli inferiori a N.

Si potrebbe scrivere questa soluzione a 54 byte:

Select[Range@#,PrimeQ@#&&(PrimeQ[#+2]||PrimeQ[#-2])&]&

In questo esempio, la funzione PrimeQviene utilizzata tre volte.

Assegnando PrimeQun nome di variabile, il conteggio dei byte può essere ridotto. Entrambi i seguenti sono 48 byte (54 - 6 byte):

Select[p=PrimeQ;Range@#,p@#&&(p[#+2]||p[#-2])&]&
Select[Range@#,(p=PrimeQ)@#&&(p[#+2]||p[#-2])&]&

2

Per ottenere un elenco di valori-chiave crescente, utilizzare Sortinvece diSortBy

Per elenchi come list = {{1, "world"}, {0, "universe"}, {2, "country"}}, le seguenti tre affermazioni sono quasi equivalenti.

SortBy[list,#[[1]]&]
list~SortBy~First
Sort@list

Combina SelecteSortBy

A volte dobbiamo selezionare le voci da un set più grande e ordinarle per trovare un minimo / massimo. In alcune circostanze , due operazioni potrebbero essere combinate in una.

Ad esempio, per un minimo, le seguenti due affermazioni sono quasi equivalenti.

SortBy[Select[l,SomeFormula==SomeConstant&],SortValue&]
SortBy[l,SortValue+99!(SomeFormula-SomeConstant)^2&]

e

SortBy[Select[l,SomeFormula!=SomeConstant&],SortValue&]
SortBy[l,SortValue+1/(SomeFormula-SomeConstant)&]

1/0è ComplexInfinity, che è "più grande" di tutti i numeri reali.

Per un elenco di valori-chiave, ad esempio:

{SortValue,#}&/@SortBy[Select[l,SomeFormula==SomeConstant],SortValue&]
Sort[{SortValue+99!(SomeFormula-SomeConstant)^2,#})&/@l]

2

Risolvi e riduci: elenco automatico delle variabili

Quando l'elenco di variabili per Solvee Reduceviene omesso, risolvono per tutte le variabili libere nelle espressioni. Esempi:

Solve[x^4==1]
(*    {{x -> -1}, {x -> -I}, {x -> I}, {x -> 1}}    *)
(*    two bytes saved on Solve[x^4==1,x]            *)

Solve[x^2+y^2==25,Integers]
(*    {{x -> -5, y -> 0}, {x -> -4, y -> -3}, {x -> -4, y -> 3}, {x -> -3, y -> -4},
       {x -> -3, y -> 4}, {x -> 0, y -> -5}, {x -> 0, y -> 5}, {x -> 3, y -> -4},
       {x -> 3, y -> 4}, {x -> 4, y -> -3}, {x -> 4, y -> 3}, {x -> 5, y -> 0}}    *)
(*    six bytes saved on Solve[x^2+y^2==25,{x,y},Integers]                         *)

Reduce[x^2+y^2<25,Reals]
(*    -5 < y < 5 && -Sqrt[25 - y^2] < x < Sqrt[25 - y^2]    *)
(*    six bytes saved on Reduce[x^2+y^2<25,{x,y},Reals]     *)

In particolare Solvesul Integers, NonNegativeIntegerse PositiveIntegersè estremamente potente per problemi di enumerazione.


1

Valori standard

I valori predefiniti gestiscono gli argomenti del modello mancanti in modo efficiente. Ad esempio, se vogliamo modellare la corrispondenza Exp[c_*x]in una regola per qualsiasi valore di c, l'ingenuo

Exp[x] + Exp[2x] /. {Exp[c_*x] -> f[c], Exp[x] -> f[1]}
(*    f[1] + f[2]    *)

utilizza molti più byte rispetto a quando utilizziamo il valore predefinito cogni volta che manca:

Exp[x] + Exp[2 x] /. Exp[c_.*x] -> f[c]
(*    f[1] + f[2]    *)

L'uso di un default è indicata con un punto dopo il modello: c_..

I valori predefiniti sono associati alle operazioni: nell'esempio sopra, l'operazione è Timesin c_.*xe quindi un valore mancante per c_viene preso dal valore predefinito associato Times, che è 1. Per Plus, il valore predefinito è 0:

Exp[x] + Exp[x + 2] /. Exp[x + c_.] -> f[c]
(*    f[0] + f[2]    *)

Per gli Poweresponenti, il valore predefinito è 1:

x + x^2 /. x^n_. -> p[n]
(*    p[1] + p[2]    *)
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.