Immutable Lists

Scala makes it easier and faster to access the first element of a list using the head method. Everything except the first element can be accessed using the tail method. Accessing the last element of the list requires traversing the list and so is more expensive than accessing the head and the tail. So, most operations on the list are structured around operations on the head and tail.

Let’s continue with the feeds example to learn about List. We can maintain an ordered collection of the feeds using a List:

 
val​ feeds = ​List​(​"blog.toolshed.com"​, ​"pragdave.me"​, ​"blog.agiledeveloper.com"​)

This creates an instance of List[String]. We can access the elements of the List using an index from 0 to list.length - 1. When we invoke feeds(1), we’re using List’s apply method. Thus, feeds(0) is a short form for feeds.apply(0). To access the first element, we can use either feeds(0) or the head method:

 
println(s​"First feed: ${feeds.head}"​)
 
println(s​"Second feed: ${feeds(1)}"​)

The output from the code is shown here:

 
First feed: blog.toolshed.com
 
Second feed: pragdave.me

If we want to prefix an element—that is, place it in the front of the list—we can use the special method ::. Read a :: list as “prefix a to the list.” This method is an operation on the list, even though the list follows the operator; see Method Name Convention for details on how this works.

 
val​ prefixedList = ​"forums.pragprog.com/forums/87"​ :: feeds
 
println(s​"First Feed In Prefixed: ${prefixedList.head}"​)

The output from the previous code is shown here:

 
First Feed In Prefixed: forums.pragprog.com/forums/87

Suppose we want to append a list, say listA, to another, say list. We would achieve that by actually prefixing list to the listA using the ::: method. So, the code would be list ::: listA and would read “prefix list to listA.” Since lists are immutable, we did not affect either one of the previous lists. We simply created a new one with elements from both. Here’s an example of appending:

 
val​ feedsWithForums =
 
feeds ::: ​List​(​"forums.pragprog.com/forums/87"​,
 
"forums.pragprog.com/forums/246"​)
 
println(s​"First feed in feeds with forum: ${feedsWithForums.head}"​)
 
println(s​"Last feed in feeds with forum: ${feedsWithForums.last}"​)

And here’s the output:

 
First feed in feeds with forum: blog.toolshed.com
 
Last feed in feeds with forum: forums.pragprog.com/forums/246

Again, the method ::: is called on the list that follows the operator.

To append an element to our list, we can use the same ::: method. We place the element we’d like to append into a list and prefix the original list to it:

 
val​ appendedList = feeds ::: ​List​(​"agilelearner.com"​)
 
println(s​"Last Feed In Appended: ${appendedList.last}"​)

We should see this output:

 
Last Feed In Appended: agilelearner.com

Notice that to append an element or a list to another list, we actually used the prefix operator on the latter. The reason for this is that it’s much faster to access the head element of a list than to traverse to its last element. So, the same result is achieved but with better performance.

To select only feeds that satisfy some condition, use the filter method. If we want to check whether all feeds meet a certain condition, we can use forall. If, on the other hand, we want to know whether any feed meets a certain condition, exists will help us.

 
println(s​"Feeds with blog: ${feeds.filter( _ contains "​blog​" ).mkString("​, ​")}"​)
 
println(s​"All feeds have com: ${feeds.forall( _ contains "​com​" )}"​)
 
println(s​"All feeds have dave: ${feeds.forall( _ contains "​dave​" )}"​)
 
println(s​"Any feed has dave: ${feeds.exists( _ contains "​dave​" )}"​)
 
println(s​"Any feed has bill: ${feeds.exists( _ contains "​bill​" )}"​)

We’ll get this:

 
Feeds with blog: blog.toolshed.com, blog.agiledeveloper.com
 
All feeds have com: true
 
All feeds have dave: false
 
Any feed has dave: true
 
Any feed has bill: false

Suppose we want to know the number of characters we need to display each feed name. We can use the map method to work on each element to get a list of the result, as shown here:

 
println(s​"Feed url lengths: ${feeds.map( _.length ).mkString("​, ​")}"​)

Here’s the output:

 
Feed url lengths: 17, 21, 23

If we’re interested in the total number of characters of all feeds put together, we can use the foldLeft method like this:

 
val​ total = feeds.foldLeft(0) { (total, feed) => total + feed.length }
 
println(s​"Total length of feed urls: $total"​)

The output from the previous code is shown here:

 
Total length of feed urls: 61

Notice that although the previous method is performing the summation, it did not deal with any mutable state. It’s pure functional style. A new updated value was accumulated as the method progressed through the elements in the list without changing anything, however.

The foldLeft method will invoke the given function value (code block) for each element in the list, starting from the left. It passes two parameters to the function value. The first parameter is a partial result from the execution of the function value for the previous element, which is why it’s called folding—it’s as if the list is folded into the result of these computations. The second parameter is an element in the list. The initial value for the partial result is provided as the parameter to the method (Zero in this example). The foldLeft method forms a chain of elements and carries the partial result of computation in the function value from one element to the next, starting from the left. Similarly, foldRight will do the same, starting at the right.

Scala provides alternate methods to make the previous methods concise. The method /: is equivalent to foldLeft and : to foldRight. Here’s the previous example written using /::

 
val​ total2 = (0 /: feeds) { (total, feed) => total + feed.length }
 
println(s​"Total length of feed urls: $total2"​)

The output from the previous code is shown here:

 
Total length of feed urls: 61

Programmers either love this conciseness, like I do, or hate it; I don’t think there will be anything in between.

We can reach out to Scala conventions here and make the code even more concise as follows:

 
val​ total3 = (0 /: feeds) { _ + _.length }
 
println(s​"Total length of feed urls: $total3"​)

Here’s the output:

 
Total length of feed urls: 61

You saw some interesting methods of List in this section. There are several other methods in List that provide additional capabilities. For a complete documentation, refer to “The Scala Language API” in Appendix 2, Web Resources.

The colons in these method names have great significance in Scala and it’s quite important to grok that; let’s explore that next.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.116.43