Dicas para jogar golfe em Scala

24

Que dicas gerais você tem para jogar golfe em Scala? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos para Scala (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

(Esta é uma cópia vergonhosa de ... em Python)

Usuário desconhecido
fonte

Respostas:

5

isenção de responsabilidade: partes dessas respostas são generalizações de outras respostas encontradas aqui.

Use lambdas sem especificar seus tipos de argumento

É permitido enviar algo como isto: em a=>a.sizevez de (a:String)=>a.size.

Use símbolos ASCII como identificadores.

Estes incluem !%&/?+*~'-^<>|. Como não são letras, são analisados ​​separadamente quando estão ao lado de letras.

Exemplos:

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

Use Set em vez de contém

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

Isso é possível porque Set[A] extends (A => Boolean).

Use uma função ao curry quando precisar de dois argumentos.

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

Use a _sintaxe-quando possível

As regras para isso são um tanto obscuras, às vezes é preciso brincar um pouco para encontrar o caminho mais curto.

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

Use aplicação parcial

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

Use em ""+vez detoString

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

Use strings como sequências

"" Às vezes, é a maneira mais curta de criar uma sequência vazia se você não se importa com o tipo de actula

Use o BigInt para converter números de e para strings

A maneira mais curta de converter um número em uma string em uma base diferente da base 10 é através do toString(base: Int)método do BigInt

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

Se você deseja converter uma string em um número, use BigInt.apply(s: String, base: Int)

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

Esteja ciente de que isso retorna um BigInt, que pode ser usado como um número na maioria das vezes, mas não pode ser usado como um índice para uma sequência, por exemplo.

Use Seq para criar sequências

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

Use seqüências de caracteres para seqüências de caracteres:

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

Faça uso do Stream para infinitas sequências

Alguns desafios pedem o n-ésimo elemento de uma sequência infinita. Stream é o candidato perfeito para isso. Lembre-se de que Stream[A] extends (Int => A), isto é, um fluxo é uma função de um índice para o elemento nesse índice.

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

Use operadores simbólicos em vez de suas contrapartes prolixo

:\e em :/vez de foldRightefoldLeft

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

hashCode -> ##

throw new Error() -> ???

Use &e em |vez de &&e||

Eles funcionam da mesma forma para booleanos, mas sempre avaliarão ambos os operandos

Alias ​​long method como funções

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

Conheça as funções na biblioteca padrão

Isso se aplica especialmente aos métodos de coleções.

Métodos muito úteis são:

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

A maneira mais curta de repetir algo é com 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
fonte
10

identificador suspeito:?

Você pode usar ? como identificador:

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

Aqui, ele não salva nada, porque você não pode colocá-lo no sinal de igual:

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

Mais tarde, porém, muitas vezes ele salva um caractere, pois você não precisa de um delimitador:

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

No entanto, geralmente é difícil de usar:

       print(?size)
3
       print(?size-5)
<console>:12: error: Int does not take parameters
       print(?size-5)
              ^
Usuário desconhecido
fonte
9

Colecções

A primeira escolha para uma coleção aleatória é geralmente a Lista . Em muitos casos, você pode substituí-lo por Seq , que salva instantan um caractere. :)

Ao invés de

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

e, enquanto s.head e s.tail são mais elegantes no código usual, s(0)são novamente um caractere menor que s.head.

Ainda mais curto em alguns casos - dependendo da funcionalidade necessária, há uma tupla:

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

salvando 3 caracteres imediatamente e para acessar:

s(0)
t._1

é o mesmo para acesso direto ao índice. Mas, para conceitos elaborados, as tuplas falham:

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

atualizar

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

Na declaração de parâmetro, Int * salva 4 caracteres sobre Seq [Int]. Não é equivalente, mas, às vezes, o Int * serve.

Usuário desconhecido
fonte
8

Você geralmente pode usar em mapvez de foreach:

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

pode ser substituído por

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

A única diferença é o tipo de retorno ( Unitvs List[Unit]), no qual você não está interessado de qualquer maneira ao usar foreach.

Luigi Plinge
fonte
7

definir tipos mais curtos:

Se você tiver várias declarações de um tipo, como

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

é mais curto definir um alias de tipo e usá-lo:

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

O comprimento original é 3 * 6 = 18 O código de substituição é 8 (tipo S =;) + 6 + 3 * 1 (= novo comprimento) = 17

se (n * comprimento <8 + comprimento + n), é uma vantagem.

Para classes instanciadas através de uma fábrica, podemos definir um nome de variável mais curto para apontar para esse objeto. Ao invés de:

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

nós podemos escrever

val A=Array;val a=A(A(1,2),A(3,4))
Usuário desconhecido
fonte
Isso também se aplica ao C ++, #definepor exemplo, mas admito que seja bom defe que valseja mais curto.
Matthew Leia
Hum. defé a palavra-chave para definir um método, e uma tradução simples para c ++ valé 'const', e é uma declaração, mas o tipo geralmente é inferido. O encurtamento é, no primeiro caso, o type=que está mais próximo typedef- não é? O segundo exemplo não é meu e é novo para mim. Eu tenho que tomar cuidado, onde usá-lo.
usuário desconhecido
typedef long long ll;é o mesmo que #define ll long long, então o último é menor em 1. Mas sim, typedeffunciona. Olhando para o valexemplo novamente, eu definitivamente o interpretei mal. Parece ainda menos específico do Scala. x = thingWithAReallyLongComplicatedNameForNoReasoné uma estratégia bastante geral: P
Matthew Leia
@userunknown Quando você instancia um Listou Arrayetc com sintaxe, val x = List(1,2,3)está chamando o applymétodo no Listobjeto. (Essa técnica para criação de objetos é conhecida como "método de fábrica", em contraste com o uso de um construtor new.) Portanto, acima, estamos apenas criando uma nova variável que aponta para o mesmo objeto singleton que o nome da variável Array. Como é a mesma coisa, todos os métodos, inclusive apply, estão disponíveis.
Luigi Plinge 12/11/11
7

Use a sintaxe infix para remover a necessidade de .caracteres. Você não precisa de espaços, a menos que os itens adjacentes estejam em caracteres alfanuméricos ou em caracteres de operador (veja aqui ) e não separados por caracteres reservados (colchetes, vírgulas etc.).

Por exemplo

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

Os literais truee falsesão mais curtos para escrever como 2>1verdadeiro e 1>2falso

triggerNZ
fonte
7

Chame duas vezes a mesma função para inicialização:

val n,k=readInt

(Visto em outro lugar, mas não é possível encontrá-lo agora).

Usuário desconhecido
fonte
6

Renomeie métodos, se o nome for longo e se forem usados ​​várias vezes - exemplo do mundo real:

 x.replaceAll(y,z)

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

Dependendo da possibilidade de salvar 'S = String' também em locais diferentes, isso só será econômico se você substituir pelo menos replaceAll 3 vezes.

Usuário desconhecido
fonte
3

Inicialize várias variáveis ​​de uma só vez usando uma tupla:

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

vs.

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

Você também pode usar em vez de usar =>para definições de função.

Varon
fonte
11
Olá e bem-vindo ao PPCG. Como na maioria das vezes, as respostas são contadas em bytes, em vez de caracteres, sua dica tem apenas um escopo limitado. Eu abordaria isso e também adicionaria um título de dica, como Definições de funções de encurtamento em desafios de golfe com códigos baseados em contagem de caracteres .
Jonathan Frech 10/09