Over a million developers have joined DZone.

Scala snippets 2: List Symbol Magic

· Java Zone

Discover how AppDynamics steps in to upgrade your performance game and prevent your enterprise from these top 10 Java performance problems, brought to you in partnership with AppDynamics.

The following other snippets are also available:

  1. Scala snippets 1: Folding

In Scala every symbol can be a function, so overloading operators (which isn't really overloading, since operators are already methods) is very easy and is something which you see in many libraries. In this snippet we'll just explore a couple of the overloaded methods that make working with lists much easier.

So lets get started and look at the ++ operator. First, like we always do, lets create a list.

scala> val list = 0 until 10 toList
list: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
 
scala> val list2 = 10 to 0 by -1 toList
list2: List[Int] = List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

And just walk through the operators from here: http://www.scala-lang.org/api/2.11.1/index.html#scala.collection.immutab...

The first operator we'll look at is ++. With this operator we can add two lists together, and return a new one:

scala> val list3 = list ++ list2
list3: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 
scala> val list3 = list2 ++ list
list3: List[Int] = List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Note that you don't have to add the same types. Scala will automatically select the most relevant superclass.

scala> val list1 = 0 to 10 toList
list1: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> val list2 = 10 to 0 by -1 toList
list2: List[Int] = List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 
scala> val list3 = list1.asInstanceOf[List[Double]]
list3: List[Double] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> list3 ++ list2
res4: List = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

As you can see AnyVal is the most common supertype of both Int and Double so that one gets selected.

Now that we've seen the ++ operator lets look at one almost the same the ++: operator.With this operator we have the same semantics as ++ but this time the type of the result is determined by the right operand instead of the left one:

scala> vector1
res14: Vector[Int] = Vector(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
 
scala> list1
res15: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> vector1 ++ list1
res16: scala.collection.immutable.Vector[Int] = Vector(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> vector1 ++: list1
res17: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

On to the next two operators :+ and +:. With these two operators we can append and prepend an element to a list:

scala> 999 +: list1
res27: List[Int] = List(999, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> list1 :+ 999
res28: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 999)

Simple right? Note that the : is always on the side of the list (target). The same goes for the ++: operator we saw earlier.

What more do we have? :: and :::. Both these operators add something to the beginning of a list. The :: operator adds a single element, and the ::: operator add a complete list. So basically they are the same as the +: and the ++ operator. The main change is that ++ and +: can be used with Traversable and ::: and :: can only be used with a list.

scala> 11 +: list1
res38: List[Int] = List(11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> list1
res39: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> 11 +: list1
res40: List[Int] = List(11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> list2
res41: List[Int] = List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 
scala> list1 ::: list2
res43: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

And then we've pretty much covered all except :\ and :/. These functions allow you to fold ([a href="http://www.smartjava.org/content/scala-snippets-1-folding" style="color: rgb(34, 98, 164); outline-style: none; text-decoration: none;"]see here for more) an list. :\ folds from right to left and :/ folds from left to right.

scala> list1
res50: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 
scala> (1 /: list1)((r,i) => {println(i);i+r})
0
1
2
3
4
5
6
7
8
9
10
res51: Int = 56
 
scala> (list1 :\ 1)((i,r) => {println(i);i+r})
10
9
8
7
6
5
4
3
2
1
0
res52: Int = 56

As you can see the folding direction determines whether the elements are processed from beginning to end or backwards.

And that's it for this small snippet.

The Java Zone is brought to you in partnership with AppDynamics. AppDynamics helps you gain the fundamentals behind application performance, and implement best practices so you can proactively analyze and act on performance problems as they arise, and more specifically with your Java applications. Start a Free Trial.

Topics:

Published at DZone with permission of Jos Dirksen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}