Zeroing on to the Scala List

Scala Zero Hour: Lists

Reading Time: 6 minutes

A class for immutable linked lists representing ordered collections of elements of type. This class comes with two implementing case classes scala.Nil and scala.:: that implement the abstract members isEmpty, head and tail. This class is optimal for,last-in-first-out (LIFO) stack-like access patterns.

Given below are a few examples

val myList = List(3, 2, 1) 
myList: List[Int] = List(1, 2, 3, 4)

val myListwith4 = 4 :: myList // re-uses mainList
myList4: List[Int] = List(4, 1, 2, 3, 4)

val myList42 = 42 :: myList4
myList42: List[Int] = List(42,4, 1, 2, 3, 4) //also re-uses

val myListtail = MyList42.tail // tail previous list
mylisttail: List[Int] = List(4, 1, 2, 3, 4)

Lists are immutable, they behave like Java strings, when you call a method on a list that might seem by its name to imply the list will mutate, it instead
creates and returns a new list with the new value. For example, List has a method named `:::’ for list concatenation.

Here’s how you use it:

 val oneTwo = List(1, 2)
oneTwo: List[Int] = List(1, 2)

val threeFour = List(3, 4)
threeFour: List[Int] = List(3, 4)

val oneTwoThreeFour = oneTwo ::: threeFour
oneTwoThreeFour: List[Int] = List(1, 2, 3, 4)

oneTwoThreeFour
res1:List[Int] = List(1, 2, 3, 4)

Different ways to create a List

You can create a Scala List in several different ways. Here’s the Lisp-style approach to creating a List:

scala> val list = 1 :: 2 :: 3 :: Nil 
list: List[Int] = List(1, 2, 3)

Here’s the Java-style approach to creating a Scala List:

scala> val list = List(1,2,3)
x: List[Int] = List(1, 2, 3)

A few notes about these approaches:

  • The first approach shows the “cons” syntax, which, as I mentioned, is the Lisp style of creating a list.
  • The :: method takes two arguments, a “head”, which is a single element, and a “tail”, which is a List.
  • As you can see, Scala can usually infer the type of a List very well.

Basic Methods

The ‘head’ method

scala> val a:List[Int]=List(1,3,2)                                                                                a: List[Int] = List(1, 3, 2)

scala> a.head res13: Int = a

The ‘tail’ method

This returns the last element of a Scala list.

scala> a.tail
res14: List[Int] = List(2,3)

The ‘isEmpty’ method

If the list is empty, this returns a Boolean true; otherwise, false.

scala> val a:List[Int]=List(1,3,2)                                                                                a: List[Int] = List(1, 3, 2)
scala> a.isEmpty
res15: Boolean = false

The ‘range’ method

You can also create a List with its range method:

scala> val x = List.range(1,10) 
x: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

The range function can also take a third argument which serves as a “step” value when creating the List.

scala> val x = List.range(0,10,2) 
x: List[Int] = List(0, 2, 4, 6, 8)

The ‘fill’ method

You can also create a new List with its fill method:

scala> val x = List.fill(3)("foo") 
x: List[java.lang.String] = List(foo, foo, foo)

Concatenating Lists in Scala

We can join or concatenate two Scala lists in one of three ways. Let’s take two lists for this:

scala> val a=List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b=List(4,5,6)
b: List[Int] = List(4, 5, 6)

The ::: Operator

scala> a:::b
res0: List[Int] = List(1, 2, 3, 4, 5, 6)

The List.:::() Method

We can call the :::() method on the first list.

scala> a.:::(b)
res2: List[Int] = List(4, 5, 6, 1, 2, 3)
scala> a
res3: List[Int] = List(1, 2, 3)

The List.concat() Method

We can also call the concat() method on List in Scala Collections. We pass both the lists as arguments.

scala> List.concat(a,b)
res5: List[Int] = List(1, 2, 3, 4, 5, 6)

Tabulating a Function

Using the List.tabulate() method with a function, we can tabulate a Scala list. The first argument specifies the dimensions; the second describes the elements(computed from a function).

scala> val g=List.tabulate(7)(n=>n*2)
g: List[Int] = List(0, 2, 4, 6, 8, 10, 12)

We can also pass more than one size argument Reversing a Scala List:

scala> val h=List.tabulate(3,7)(_*_)
h: List[List[Int]] = List(List(0, 0, 0, 0, 0, 0, 0), List(0, 1, 2, 3, 4, 5, 6), List(0, 2, 4, 6, 8, 10, 12))

 Reversing a Scala List

This reverses the order of elements in a list using the List.reverse method.

scala> list
res6: List[Int] = List(1, 2, 3)
scala> list.reverse
res7: List[Int] = List(3, 2, 1)
scala> list
res8: List[Int] = List(1, 2, 3)

As you can see in above example that the reverse function is not making any modification in our List a, if we want to store reverse list somewhere, we have to store it in any variable.

Foreach: Iteration of Lists

A very common way to iterate on Scala lists is  foreach method. The foreach takes a procedure as the right operand which take return type as an Unit. It applies the procedure to each List element.

Here’s an example showing how to use the foreach function to print every item in a List:

scala> val mylist = List(1,2,3)  
mylist: List[Int] = List(1, 2, 3)

scala> mylist.foreach { println }
1
2
3

Here is an example to calculate sum of all the elements in list using foreach:

scala> var sum = 0
sum: Int = 0
scala> val mylist = List(1,2,3)
mylist: List[Int] = List(1, 2, 3)
scala> mylist.foreach(sum += _)
scala> println(sum)
6

Filtering the scala List

The filter method is used to filter any list’s elements through any conditions like in below example :, we filter the list by selecting theeven elements

scala> val mylist = List(1,2,3,4,5,6,7) 
mylist: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
scala> val evenElements = mylist.filter(a => a % 2 == 0)
evenElements: List[Int] = List(2, 4, 6)

take while

The takeWhile condition is same, lets have a look at below example :

scala> val mylist = List(1,2,3,4,5,6,7) 
mylist: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
scala> val mylist1 = mylist.takeWhile(a => a < 6) y: List[Int] = List(1, 2, 3, 4, 5)

The List map function

The map function in scala used to transform all the elements of an list based on any defined function.

scala> val mylist = List(1,2,3) 
mylist: List[Int] = List(2,3,4)
scala> val mappedlist = x.map(a => a * 2)
mappedlist: List[Int] = List(4,6,8)

using the Scala wildcard character (_) instead of a new variable name:

scala> val mylist = x.map(_ * 2) 
mylist: List[Int]

Here are some other examples of List mapping

scala> val namelist = List("shubham", "azmat", "sakshi") 
namelist: List[java.lang.String] = List(Shubham, Azmat, Sakshi)
scala> val lowerlist = namelist.map(_.toLowerCase)
lowerlist: List[java.lang.String] = List(shubham, azmat,sakshi)
scala> val upperlist = names.map(_.toUpperCase)
upperlist: List[java.lang.String] = List(SHUBHAM, AZMAT, SAKSHI)

The List flatMap function

Now, let’s move on to flatMap(), so as the name signifies flatMap() flatten the hierarchy level by one level each time it is applied. A flatMap method also takes a function but, the function in this case returns a sequence. The flatMap() operation flattens the result in the resultant list, it applies that function to each element 

scala> val list = List(1, 2, 3, 4)
list: List[Int] = List(1, 2, 3, 4)

scala> val addUnity = (x: Int) => List(x *2, x - 1)
addUnity: Int => List[Int] = <function1>

scala> list.flatMap(addUnity)
res3: List[Int] = List(2, 0, 4, 1, 6, 2, 8, 3)

 map vs flatMap function

 now let’s see what happens when we apply map() and flatMap() operations…

scala> list.flatMap(addUnity)
res3: List[Int] = List(2, 0, 4, 1, 6, 2, 8, 3)

scala> list.map(addUnity)
res4: List[List[Int]] = List(List(2, 0), List(4, 1), List(6, 2), List(8, 3))

This is the difference between an map and flatMap function , an map function gives you an List of List and flatmap maps all the elements , applied function on them and flattened the List.

 Methods on a List in Scala

We can also call the following methods on a Scala List: (Note that these don’t modify the Lists)

a. def +(elem: A): List[A]

This postpends an element to the Scala list.

scala> a.+("2")
res12: String = List(1, 2, 3)2

b. def addString(b: StringBuilder): StringBuilder

This appends all elements of a Scala list to a String Builder.

scala> var b=new StringBuilder()
b: StringBuilder =
scala> a.addString(b)
res19: StringBuilder = 123
scala> a
res20: List[Int] = List(1, 2, 3)
scala> b
res21: StringBuilder = 123

c. def addString(b: StringBuilder, sep: String): StringBuilder

This does the same thing, except with a separator between the elements.
Let’s first reset b to an empty string.

scala> b=new StringBuilder()
b: StringBuilder =
scala> a.addString(b,"*")
res23: StringBuilder = 1*2*3

d. def apply(n: Int): A

This selects an element in the Scala List by its index.

scala> a.apply(2)
res24: Int = 3

e. def contains(elem: Any): Boolean

If the list contains a certain element, this returns true; otherwise, false.

scala> a.contains(2)
res25: Boolean = true
scala> a.contains(4)
res26: Boolean = false

f. def drop(n: Int): List[A]

This returns all elements except the first n.

scala> var j=List(1,1,4,1,3,2,1)
j: List[Int] = List(1, 1, 4, 1, 3, 2, 1)
scala> j.drop(2)
res27: List[Int] = List(4, 1, 3, 2, 1)

g. def dropRight(n: Int): List[A]
This returns all elements except the last n.

scala> j.dropRight(2)
res28: List[Int] = List(1, 1, 4, 1, 3)

h. def distinct: List[A]

Distinct returns a new List without duplicates.

scala> j.distinct
res29: List[Int] = List(1, 4, 3, 2)

i. def init: List[A]

This returns all elements except the last.

scala> a.init
res30: List[Int] = List(1, 2)

j. def length: Int

This returns a List’s length.

scala> a.length
res31: Int = 3

k. def max: A

This returns the highest element.

scala> a.max
res32: Int = 3

l. def min: A

This returns the lowest element.

scala> a.min
res33: Int = 1

m. def mkString: String

This displays all elements of a list in a String.

scala> a.mkString
res34: String = 123

n. def flatten: List[A]

Use the flatten method to convert a list of lists into a single list. To demonstrate this, first create a list of lists:

scala> val list = List(List(1,2), List(3,4))
list: List[List[Int]] = List(List(1, 2), List(3, 4))

Calling the flatten method on this list of lists creates one new list:

list.flatten
res0: List[Int] = List(1, 2, 3, 4)

flatten does what its name implies, flattening the lists held inside the outer list into one resulting list

o. def sum: A

This returns the sum of all elements.

scala> a.sum
res36: Int = 6

p. def equals(that: Any): Boolean

This compares two sequences.

scala> a.equals(b)
res53: Boolean = false
scala> a.equals(List(1,2,3))
res55: Boolean = true

q. def toArray: Array[A]

This returns an Array from a List.

scala> a.toArray
res37: Array[Int] = Array(1, 2, 3)

References :

Written by 

Shubham Goyal is a Data Scientist at Knoldus Inc. With this, he is an artificial intelligence researcher, interested in doing research on different domain problems and a regular contributor to society through blogs and webinars in machine learning and artificial intelligence. He had also written a few research papers on machine learning. Moreover, a conference speaker and an official author at Towards Data Science.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading