Consejos para jugar al golf en Scala

24

¿Qué consejos generales tienes para jugar al golf en Scala? Estoy buscando ideas que puedan aplicarse a los problemas de código de golf en general que sean al menos algo específicos de Scala (por ejemplo, "eliminar comentarios" no es una respuesta). Por favor, publique un consejo por respuesta.

(Esta es una copia descarada de ... en Python)

usuario desconocido
fuente

Respuestas:

5

descargo de responsabilidad: partes de estas respuestas son generalizaciones de otras respuestas que se encuentran aquí.

Use lambdas sin especificar sus tipos de argumento

Está permitido enviar algo como esto: en a=>a.sizelugar de (a:String)=>a.size.

Use símbolos ascii como identificadores.

Estos incluyen !%&/?+*~'-^<>|. Como no son letras, se analizan por separado cuando están al lado de las letras.

Ejemplos:

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

Use Set en lugar de contiene

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

Esto es posible porque Set[A] extends (A => Boolean).

Use una función curry cuando necesite dos argumentos.

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

Use la _sintaxis cuando sea posible

Las reglas para esto son algo oscuras, a veces hay que jugar un poco para encontrar el camino más corto.

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

Usar aplicación parcial

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

Usar en ""+lugar detoString

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

Usa cadenas como secuencias

"" a veces es la forma más corta de crear una secuencia vacía si no te importa el tipo de actula

Use BigInt para convertir números hacia y desde cadenas

La forma más corta de convertir un número a una cadena en una base que no sea la base 10 es a través del toString(base: Int)método de BigInt

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

Si desea convertir una cadena en un número, use BigInt.apply(s: String, base: Int)

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

Tenga en cuenta que esto devuelve un BigInt, que se puede usar como un número la mayoría de las veces, pero no se puede usar como índice para una secuencia, por ejemplo.

Usa Seq para crear secuencias

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

Utilice cadenas para secuencias de caracteres:

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

Utiliza Stream para secuencias infinitas

Algunos desafíos requieren el enésimo elemento de una secuencia infinita. Stream es el candidato perfecto para esto. Recuerde que Stream[A] extends (Int => A), es decir, una secuencia es una función de un índice al elemento en ese índice.

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

Use operadores simbólicos en lugar de sus homólogos verbales

:\y en :/lugar de foldRightyfoldLeft

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

hashCode -> ##

throw new Error() -> ???

Use &y en |lugar de &&y||

Funcionan igual para los booleanos, pero siempre evaluarán ambos operandos

Método largo alias como funciones

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

Conozca las funciones en la biblioteca estándar.

Esto se aplica especialmente a los métodos de colecciones.

Los métodos muy útiles son:

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
corvus_192
fuente
11

La forma más corta de repetir algo es con Seq.fill.

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

Identificador sospechoso:?

Puedes usar ? como identificador:

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

Aquí no te ahorra nada, porque no puedes pegarlo al signo igual:

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

Pero más adelante, a menudo guarda un carácter, ya que no necesita un delimitador:

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

Sin embargo, a menudo es difícil de usar:

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

Colecciones

La primera opción para una colección aleatoria es a menudo Lista . En muchos casos, puede reemplazarlo con Seq , que ahorra un carácter instantáneo. :)

En lugar de

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

y, aunque s.head y s.tail es más elegante en el código habitual, s(0)nuevamente es un carácter más corto que s.head.

Incluso más corto en algunos casos, dependiendo de la funcionalidad necesaria es una tupla:

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

guardar 3 caracteres inmediatamente y para acceder a:

s(0)
t._1

Es lo mismo para el acceso directo al índice. Pero para conceptos elaborados, las tuplas fallan:

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

actualizar

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

En la declaración de parámetros, Int * guarda 4 caracteres sobre Seq [Int]. No es equivalente, pero a veces, Int * lo hará.

usuario desconocido
fuente
8

Por lo general, puede usar en maplugar de foreach:

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

puede ser reemplazado con

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

La única diferencia es el tipo de retorno ( Unitvs List[Unit]), que no le interesa de todos modos cuando lo usa foreach.

Luigi Plinge
fuente
7

definir tipos más cortos:

Si tiene varias declaraciones de un tipo, como

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

es más corto definir un alias de tipo y usarlo en su lugar:

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

La longitud original es 3 * 6 = 18 El código de reemplazo es 8 (tipo S =;) + 6 + 3 * 1 (= nueva longitud) = 17

if (n * length <8 + length + n), entonces es una ventaja.

Para las clases que se instancian a través de una fábrica, podemos establecer un nombre de variable más corto para apuntar a ese objeto. En lugar de:

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

podemos escribir

val A=Array;val a=A(A(1,2),A(3,4))
usuario desconocido
fuente
Esto también se aplica a C ++, #definepor ejemplo, pero admito que es bueno defy valson más cortos.
Matthew leyó el
Hm. defes la palabra clave para definir un método, y una traducción simple a c ++ para vales 'const', y es una declaración, pero a menudo se infiere el tipo. El acortamiento es en el primer caso el type=que está más cerca typedef, ¿no es así? El segundo ejemplo no es mío y es nuevo para mí. Tengo que tener cuidado, dónde usarlo.
usuario desconocido
typedef long long ll;es lo mismo que #define ll long long, por lo que este último es más corto en 1. Pero sí, typedeffunciona. Mirando el valejemplo nuevamente, definitivamente lo leí mal. Parece aún menos específico de Scala. x = thingWithAReallyLongComplicatedNameForNoReasones una estrategia bastante general: P
Matthew Lee el
@userunknown Cuando crea una instancia de Listo Arrayetc con sintaxis val x = List(1,2,3), solo está llamando al applymétodo en el Listobjeto. (Esta técnica para la creación de objetos se conoce como un "método de fábrica", en contraste con el uso de un constructor con new). Así que arriba, solo estamos creando una nueva variable que apunta al mismo objeto singleton que el nombre de la variable Array. Como es lo mismo, todos los métodos, incluidos apply, están disponibles.
Luigi Plinge
7

Use la sintaxis infija para eliminar la necesidad de .caracteres. No necesita espacios a menos que los elementos adyacentes estén en caracteres alfanuméricos o en caracteres de operador (ver aquí ), y no estén separados por caracteres reservados (corchetes, comas, etc.).

P.ej

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

Los literales truey falseson más cortos para escribir como 2>1verdadero y 1>2falso

triggerNZ
fuente
7

Llame dos veces la misma función para la inicialización:

val n,k=readInt

(Visto en otro lugar, pero no puedo encontrarlo ahora).

usuario desconocido
fuente
6

Cambie el nombre de los métodos, si su nombre es largo y si se usan varias veces; ejemplo del mundo real:

 x.replaceAll(y,z)

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

Dependiendo de la posibilidad de guardar 'S = String' en diferentes lugares también, esto solo será económico, si reemplaza al menos 3 veces.

usuario desconocido
fuente
3

Inicialice varias variables a la vez usando una tupla:

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

vs.

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

También puede usar en lugar de usar =>para definiciones de funciones.

Varon
fuente
1
Hola y bienvenidos a PPCG. Como la mayoría de las veces, las respuestas se cuentan en bytes en lugar de caracteres, su sugerencia solo tiene un alcance limitado. Me ocuparía de esto y también agregaría un título de punta como las definiciones de función de acortamiento en los desafíos de golf de código basados ​​en el recuento de caracteres .
Jonathan Frech