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.
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
Use ascii-symbols as identifiers.
!%&/?+*~'-^<>|. Because they arent't letters, they get parsed seperated when they're next to letters.
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
_-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
""+ instead of
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
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.
Use symbolic operators instead of their wordy counterparts
:/ instead of
a.foldLeft(z)(f) //wrong (z/:a)(f) //right a.foldRight(z)(f) //wrong (a:\z)(f) //right
throw new Error() ->
| instead of
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
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) ^
The first choice for a random collection is often List. In many cases you can replace it with Seq, which saves one character instantan. :)
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
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:
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) ^
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.
define shorter Types:
If you have multiple declarations of a type, like
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:
we can write
val A=Array;val a=A(A(1,2),A(3,4))
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).
List(1,2,3,4).filter(_ % 2 == 0) // change to: List(1,2,3,4)filter(_%2==0)
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.