Consigli per giocare a golf a Scala


24

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

(Questa è una copia spudorata di ... in Python)

Risposte:


5

disclaimer: parti di queste risposte sono generalizzazioni di altre risposte trovate qui.

Usa lambdas senza specificare i loro tipi di argomenti

È consentito inviare qualcosa del genere: a=>a.sizeanziché (a:String)=>a.size.

Usa simboli ASCII come identificatori.

Questi includono !%&/?+*~'-^<>|. Poiché non sono lettere, vengono analizzate separatamente quando si trovano accanto alle lettere.

Esempi:

a=>b       //ok
%=>%        //error, parsed as one token
% => %      //ok
val% =3     //ok
&contains+  //ok
if(x)&else* //ok

Usa Set invece di contiene

if (Seq(1,2,3,'A')contains x)... //wrong
if (Set(1,2,3,'A')(x))...         //right

Questo è possibile perché Set[A] extends (A => Boolean).

Utilizzare una funzione curry quando sono necessari due argomenti.

(a,b)=>... //wrong
a=>b=>...  //right

Utilizzare la _sintassi quando possibile

Le regole per questo sono piuttosto oscure, devi giocare un po 'in giro a volte per trovare il modo più breve.

a=>a.map(b=>b.size)) //wrong
a=>a.map(_.size)     //better
_.map(_.size)        //right

Usa un'applicazione parziale

a=>a+1 //wrong
_+1    //better, see above
1+     //right; this treats the method + of 1 as a function

Usa ""+invece ditoString

a=>a.toString //wrong
a=>a+""       //right

Usa le stringhe come sequenze

"" a volte è il modo più breve per creare una sequenza vuota se non ti interessa il tipo di actula

Usa BigInt per convertire numeri da e verso stringhe

Il modo più breve per convertire un numero in una stringa in una base diversa dalla base 10 è tramite il toString(base: Int)metodo di BigInt

Integer.toString(n,b) //wrong
BigInt(n)toString b   //right

Se vuoi convertire una stringa in un numero, usa BigInt.apply(s: String, base: Int)

Integer.parseInt(n,b) //wrong
BigInt(n,b)           //right

Tieni presente che questo restituisce un BigInt, che è utilizzabile come un numero il più delle volte, ma non può essere utilizzato come indice per una sequenza, ad esempio.

Usa Seq per creare sequenze

a::b::Nil   //wrong
List(...)   //also wrong
Vector(...) //even more wrong
Seq(...)    //right
Array(...)  //also wrong, except if you need a mutable sequence

Usa stringhe per sequenze di caratteri:

Seq('a','z') //wrong
"az"         //right

Utilizza Stream per sequenze infinite

Alcune sfide richiedono l'ennesimo elemento di una sequenza infinita. Stream è il candidato perfetto per questo. Ricorda che Stream[A] extends (Int => A), cioè, uno stream è una funzione da un indice all'elemento in quell'indice.

Stream.iterate(start)(x=>calculateNextElement(x))

Usa operatori simbolici invece delle loro controparti prolifiche

:\e :/invece di foldRightefoldLeft

a.foldLeft(z)(f) //wrong
(z/:a)(f)        //right
a.foldRight(z)(f) //wrong
(a:\z)(f)         //right

hashCode -> ##

throw new Error() -> ???

Usa &e |invece di &&e||

Funzionano allo stesso modo per i booleani, ma valuteranno sempre entrambi gli operandi

Alias ​​metodo lungo come funzioni

def r(x:Double)=math.sqrt(x) //wrong
var r=math.sqrt _            //right; r is of type (Double=>Double)

Conoscere le funzioni nella libreria standard

Ciò vale soprattutto per i metodi di raccolta.

Metodi molto utili sono:

map
flatMap
filter
:/ and :\ (folds)
scanLeft and scanRight
sliding
grouped (only for iterators)
inits
headOption
drop and take
collect
find
zip
zipWithIndex3
distinct and/or toSet
startsWith

11

Il modo più breve di ripetere qualcosa è con Seq.fill.

1 to 10 map(_=>println("hi!")) // Wrong!
for(i<-1 to 10)println("hi!") // Wrong!
Seq.fill(10)(println("hi!")) // Right!

10

identificatore sospetto:?

Puoi usare ? come identificatore:

val l=List(1,2,3)
val? =List(1,2,3)

Qui non ti salva nulla, perché non puoi attaccarlo al segno uguale:

val ?=List(1,2,3) // illegal

Ma in seguito, spesso salva un personaggio, dal momento che non è necessario un delimitatore:

print(?size)  // l.size needs a dot
def a(? :Int*)=(?,?tail).zipped.map(_-_)

Tuttavia, è spesso difficile usare:

       print(?size)
3
       print(?size-5)
<console>:12: error: Int does not take parameters
       print(?size-5)
              ^

9

collezioni

La prima scelta per una raccolta casuale è spesso Elenco . In molti casi è possibile sostituirlo con Seq , che consente di salvare un carattere istantaneo. :)

Invece di

val l=List(1,2,3)
val s=Seq(1,2,3)

e, mentre s.head e s.tail sono più eleganti nel solito codice, s(0)sono di nuovo un carattere più corto di s.head.

Ancora più breve in alcuni casi - a seconda della funzionalità necessaria è una tupla:

val s=Seq(1,2,3)
val t=(1,2,3)

salvare immediatamente 3 caratteri e per accedere a:

s(0)
t._1

è lo stesso per l'accesso diretto all'indice. Ma per concetti elaborati, le tuple falliscono:

scala> s.map(_*2)
res55: Seq[Int] = List(2, 4, 6)

scala> t.map(_*2)
<console>:9: error: value map is not a member of (Int, Int, Int)
       t.map(_*2)
         ^

aggiornare

def foo(s:Seq[Int])
def foo(s:Int*)

Nella dichiarazione dei parametri, Int * salva 4 caratteri su Seq [Int]. Non è equivalente, ma a volte Int * lo farà.


8

Di solito puoi usare mapinvece di foreach:

List("a","b","c") foreach println

può essere sostituito con

List("a","b","c") map println

L'unica differenza è il tipo di ritorno ( Unitvs List[Unit]), che non ti interessa in ogni caso durante l'utilizzo foreach.


7

definire tipi più brevi:

Se hai più dichiarazioni di un tipo, ad esempio

def f(a:String,b:String,c:String) 

è più breve definire un alias di tipo e usarlo invece:

type S=String;def f(a:S,b:S,c:S)

La lunghezza originale è 3 * 6 = 18 Il codice di sostituzione è 8 (tipo S =;) + 6 + 3 * 1 (= nuova lunghezza) = 17

if (n * lunghezza <8 + lunghezza + n), allora è un vantaggio.

Per le classi che vengono istanziate tramite una factory, possiamo impostare un nome di variabile più breve per puntare a quell'oggetto. Invece di:

val a=Array(Array(1,2),Array(3,4))

possiamo scrivere

val A=Array;val a=A(A(1,2),A(3,4))

Questo vale anche per C ++, #definead esempio, ma ammetto che è carino defe valsono più brevi.
Matteo Leggi l'

Hm. defè la parola chiave per definire un metodo, e una semplice traduzione in c ++ per valè 'const', ed è una dichiarazione, ma il tipo viene spesso dedotto. L'accorciamento è nel primo caso il type=più vicino a typedef- non è vero? Il secondo esempio non viene da me ed è nuovo per me. Devo fare attenzione, dove usarlo.
utente sconosciuto

typedef long long ll;è lo stesso di #define ll long long, quindi quest'ultimo è più corto di 1. Ma sì, typedeffunziona. Guardando di valnuovo l' esempio, l'ho sicuramente frainteso. Sembra ancora meno specifico per la Scala. x = thingWithAReallyLongComplicatedNameForNoReasonè una strategia piuttosto generale: P
Matteo Leggi l'

@userunknown Quando si crea un'istanza di a Listo Arrayetc con la sintassi, val x = List(1,2,3)si sta semplicemente chiamando il applymetodo Listsull'oggetto. (Questa tecnica per la creazione di oggetti è nota come "metodo factory", in contrasto con l'uso di un costruttore con new.) Quindi, sopra, stiamo solo creando una nuova variabile che punta allo stesso oggetto singleton del nome della variabile Array. Poiché è la stessa cosa apply, sono disponibili tutti i metodi, incluso .
Luigi Plinge,

7

Utilizzare la sintassi infix per rimuovere la necessità di .caratteri. Non sono necessari spazi a meno che gli elementi adiacenti non siano entrambi in caratteri alfanumerici o entrambi in caratteri operatore (vedere qui ) e non separati da caratteri riservati (parentesi, virgole ecc.).

Per esempio

List(1,2,3,4).filter(_ % 2 == 0) // change to:
List(1,2,3,4)filter(_%2==0)

7

I letterali truee falsesono più brevi da scrivere come 2>1per vero e 1>2per falso


7

Chiama due volte la stessa funzione per l'inizializzazione:

val n,k=readInt

(Visto da qualche altra parte, ma non riesco a trovarlo ora).


6

Rinomina metodi, se il loro nome è lungo e se vengono utilizzati più volte - esempio nel mondo reale:

 x.replaceAll(y,z)

 type S=String; def r(x:S,y:S,z:S)=x.replaceAll(y,z)

A seconda della possibilità di salvare 'S = String' anche in luoghi diversi, questo sarà economico, se lo sostituisci almeno per 3 volte.


3

Inizializza più variabili contemporaneamente usando una tupla:

var(a,b,c)=("One","Two","Three") //32 characters

vs.

var a="One";var b="Two";var c="Three" //37 characters

0

È inoltre possibile utilizzare anziché utilizzare =>per le definizioni delle funzioni.


1
Ciao e benvenuto in PPCG. Poiché la maggior parte delle volte, le risposte sono conteggiate in byte anziché in caratteri, il tuo suggerimento ha solo un ambito limitato. Vorrei affrontare questo e aggiungerei anche un titolo di suggerimento come Accorciare le definizioni delle funzioni nelle sfide del golf basato sul conteggio dei caratteri .
Jonathan Frech,
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.