Scala

Scala snippets 2: List symbol magic

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 easiers.

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[AnyVal] = 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 (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.

Reference: Scala snippets 2: List symbol magic from our JCG partner Jos Dirksen at the Smart Java blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Fair
Fair
10 years ago

there is a error
And then we’ve pretty much covered all except :\ and :/.
should be
And then we’ve pretty much covered all except :\ and /:.

Back to top button