Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Scala snippets 2: List Symbol Magic

DZone's Guide to

Scala snippets 2: List Symbol Magic

· Java Zone
Free Resource

Build vs Buy a Data Quality Solution: Which is Best for You? Gain insights on a hybrid approach. Download white paper now!

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.

Build vs Buy a Data Quality Solution: Which is Best for You? Maintaining high quality data is essential for operational efficiency, meaningful analytics and good long-term customer relationships. But, when dealing with multiple sources of data, data quality becomes complex, so you need to know when you should build a custom data quality tools effort over canned solutions. Download our whitepaper for more insights into a hybrid approach.

Topics:

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

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}