25
\$\begingroup\$

What general tips do you have for golfing in Scala? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Scala (e.g. "remove comments" is not an answer). Please post one tip per answer.

(This is a shameless copy of ... in Python)

\$\endgroup\$

12 Answers 12

5
\$\begingroup\$

disclaimer: parts of this answers are generalizations of other answers found here.

Use lambdas without specifying their argument types

It's allowed to submit something like this: a=>a.size instead of (a:String)=>a.size.

Use ascii-symbols as identifiers.

These include !%&/?+*~'-^<>|. Because they arent't letters, they get parsed seperated when they're next to letters.

Examples:

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

Use Set instead of contains

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

This is possible because Set[A] extends (A => Boolean).

Use a curried function when you need two arguments.

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

Use the _-syntax when possible

The rules for this are somewhat obscure, you have to play a little bit around sometimes to find the shortest way.

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

Use partial application

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

Use ""+ instead of toString

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

Use strings as sequences

"" is sometimes the shortest way to create an empty sequence if you don't care about the actula type

Use BigInt to convert numbers to and from strings

The shortest way to convert a number to a string in a base other than base 10 is through BigInt's toString(base: Int)method

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

If you want to convert a string to a number, use BigInt.apply(s: String, base: Int)

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

Be aware that this returns a BigInt, which is useable like a number most of the times, but can't be used as an index for a sequence, for example.

Use Seq to create sequences

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

Use Strings for Seqences of chars:

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

Make use of Stream for infinite sequences

Some challenges ask for the n-th element of an infinite sequence. Stream is the perfect candidate for this. Remember that Stream[A] extends (Int => A), that is, a stream is a function from an index to the element at that index.

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

Use symbolic operators instead of their wordy counterparts

:\ and :/ instead of foldRight and foldLeft

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

hashCode -> ##

throw new Error() -> ???

Use & and | instead of && and ||

They work the same for booleans, but will always evaluate both operands

Alias long method as functions

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

Know the functions in the standard library

This especially applies to the methods of collections.

Very useful methods are:

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
\$\endgroup\$
11
\$\begingroup\$

The shortest way of repeating something is with Seq.fill.

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

suspicious identifier: ?

You can use ? as identifier:

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

Here it doesn't save you anything, because you can't stick it to the equal sign:

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

But later on, it often saves one character, since you don't need a delimiter:

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

However, it is often tricky to use:

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

Collections

The first choice for a random collection is often List. In many cases you can replace it with Seq, which saves one character instantan. :)

Instead of

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

and, while s.head and s.tail is more elegant in usual code, s(0) is again one character shorter than s.head.

Even shorter in some cases - depending on needed functionality is a tuple:

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

saving 3 characters immediately, and for accessing:

s(0)
t._1

it is the same for direct index access. But for elaborated concepts, tuples fail:

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

update

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

In parameter declaration, Int* saves 4 characters over Seq[Int]. It is not equivalent, but sometimes, Int* will do.

\$\endgroup\$
8
\$\begingroup\$

You can usually use map instead of foreach:

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

can be replaced with

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

The only difference is the return type (Unit vs List[Unit]), which you aren't interested in anyway when using foreach.

\$\endgroup\$
7
\$\begingroup\$

define shorter Types:

If you have multiple declarations of a type, like

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

it is shorter to define a type alias, and use it instead:

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

Original length is 3*6=18 Replacement-code is 8(type S=;)+6+3*1(=new length)=17

if (n*length < 8+length+n), then it is an advantage.

For classes which are instantiated via a factory, we can set a shorter variable name to point to that object. Instead of:

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

we can write

val A=Array;val a=A(A(1,2),A(3,4))
\$\endgroup\$
  • \$\begingroup\$ This applies to C++ as well with #define for example, but I admit it's nice that def and val are shorter. \$\endgroup\$ – Matthew Read Nov 11 '11 at 18:21
  • \$\begingroup\$ Hm. def is the keyword to define a method, and a simple translation to c++ for val is 'const', and it is a declaration, but the type is often inferred. The shortening is in the first case the type= which is closer to typedef - isn't it? The second example isn't from me and it is new to me. I have to watch out, where to use it. \$\endgroup\$ – user unknown Nov 11 '11 at 19:01
  • \$\begingroup\$ typedef long long ll; is the same as #define ll long long, so the latter's shorter by 1. But yeah, typedef does work. Looking at the val example again I definitely misread it. It seems even less Scala-specific. x = thingWithAReallyLongComplicatedNameForNoReason is a pretty general strategy :P \$\endgroup\$ – Matthew Read Nov 11 '11 at 19:21
  • \$\begingroup\$ @userunknown When you instantiate a List or Array etc with syntax val x = List(1,2,3) you're just calling the apply method on the List object. (This technique for object creation is known as a "factory method", in contrast to using a constructor with new.) So above, we're just making a new variable that points to the same singleton object as the variable name Array. Since it's the same thing, all the methods, including apply, are available. \$\endgroup\$ – Luigi Plinge Nov 12 '11 at 17:36
7
\$\begingroup\$

Use infix syntax to remove the need for . characters. You don't need spaces unless adjacent items are both in alphanumeric or both in operator characters (see here), and not separated by reserved characters (brackets, commas etc).

E.g.

List(1,2,3,4).filter(_ % 2 == 0) // change to:
List(1,2,3,4)filter(_%2==0)
\$\endgroup\$
7
\$\begingroup\$

The true and false literals are shorter to write as 2>1 for true and 1>2 for false

\$\endgroup\$
7
\$\begingroup\$

Call two times the same function for initialization:

val n,k=readInt

(Seen somewhere else, but can't find it now).

\$\endgroup\$
6
\$\begingroup\$

Rename Methods, if their name is long, and if they're used multiple times - real world example:

 x.replaceAll(y,z)

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

Depending on the possibility to save 'S=String' at different places too, this will only be economical, if you replace at least replaceAll 3 times.

\$\endgroup\$
3
\$\begingroup\$

Initialize several variables at once using a tuple:

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

vs.

var a="One";var b="Two";var c="Three" //37 characters
\$\endgroup\$
0
\$\begingroup\$

You can also use instead of using => for function definitions.

\$\endgroup\$
  • \$\begingroup\$ Hello and welcome to PPCG. Since most of the time, answers are counted in bytes rather than characters, your tip only has a limited scope. I would address this and also add a tip title like Shortening function definitions in character count based code golf challenges. \$\endgroup\$ – Jonathan Frech Sep 10 '18 at 23:35

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.