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

10 Amazing Scala Collection Functions

DZone's Guide to

10 Amazing Scala Collection Functions

These 10 collection functions, ranging from min and max values to folding to flatmaps, will come in handy during your day-to-day work.

· Java Zone
Free Resource

Make it happen: rapid app development on Kubernetes as a managed service.

When I work with Scala collections, I always keep in mind that there are two types of operations that I can perform: transformation operations and actions or aggregation operations. The first type transforms a collection into some another collection. The second one type returns some value.

After this short introduction, I want to focus on particular Scala collection functions, which I count as some of the most useful and amazing parts of my everyday work. Some of these functions are to transform collections, and the rest of them return a particular value after application. And at the end of the article, I want to show you how these functions can be combined in order to solve a concrete problem.

#1 Minimum and Maximum Values

I want to start with the action function.

It’s so common a task to find a minimum or maximum value in a sequence. Of course, you may say that these kind of operations are helpful only for interview questions and algorithms, but let’s be honest, who doesn't remember these lines of code in Java?

int[] arr = {11, 2, 5, 1, 6, 3, 9}; 
int to = arr.length - 1; 
int max = arr[0]; 
for (int i = 0; i < to; i++) 
{ if (max < arr[i+1]) max = arr[i+1]; } 
System.out.println(max); 


Question: How to find maximum/minimum in a list?

Scala suggests a pretty elegant solution:

 val numbers = Seq(11, 2, 5, 1, 6, 3, 9) 
   numbers.max //11 
   numbers.min //1 


But we always work with more complex data. Let’s introduce a more advanced example, where we have a sequence of books, represented by case classes.

 case class Book(title: String, pages: Int) 
   val books = Seq( Book("Future of Scala developers", 85), 
                   Book("Parallel algorithms", 240), 
                   Book("Object Oriented Programming", 130), 
                   Book("Mobile Development", 495) ) 
   //Book(Mobile Development,495) 
   books.maxBy(book => book.pages) 
   //Book(Future of Scala developers,85) 
   books.minBy(book => book.pages) 


So as you see, minBy & maxBy functions solve problems with non-trivial data. The only thing you need to do is to choose a data property by which you want to determine minimum or maximum values.

#2 Filtering

Have you ever filtered collections? For example, say you want to get items with a price of more than $10 or you need to select the youngest employees under 24 years. All these operations imply using filtering.

Let’s start with the popular example: filter a list of numbers and get only even elements.

val numbers = Seq(1,2,3,4,5,6,7,8,9,10) numbers.filter(n => n % 2 == 0) 


What about a more complex scenario? I want to choose books where the number of pages are more than 120.

val books = Seq( Book("Future of Scala developers", 85), 
                 Book("Parallel algorithms", 240), 
                 Book("Object Oriented Programming", 130), 
                 Book("Mobile Development", 495) ) 
   books.filter(book => book.pages >= 120) 


Filtering is not much harder to apply than the min & max functions, despite the fact that filter is a function of the transformation type.

Also, there is a syntax sugar analog of the filter function. Its name is filterNot. I guess, you know what it does by its name. If not, try to substitute the filter function for filterNot in the first example.

#3 Flatten O_o

I bet, there is a huge chance that you haven’t heard about this function before! It’s easy to explain. Because its application is extremely specific. For me, it’s hard to describe this function without an example.

val abcd = Seq('a', 'b', 'c', 'd') 
   val efgj = Seq('e', 'f', 'g', 'h') 
   val ijkl = Seq('i', 'j', 'k', 'l') 
   val mnop = Seq('m', 'n', 'o', 'p') 
   val qrst = Seq('q', 'r', 's', 't') 
   val uvwx = Seq('u', 'v', 'w', 'x') 
   val yz = Seq('y', 'z') 
   val alphabet = Seq(abcd, efgj, ijkl, mnop, qrst, uvwx, yz) 
   // 
  // List(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t,
  //      u, v, w, x, y, z) 
   alphabet.flatten 


When is flatten helpful? Well, if you have a collection of collections and you want to operate with all of the elements from the collections, don’t hesitate to use flatten.

#4 Euler Diagram Functions

Don’t panic! I talk about a well-known operation: difference, intersection, union. I hope, you agree with me that these functions are good to be explained on Euler diagrams:

val num1 = Seq(1, 2, 3, 4, 5, 6) 
   val num2 = Seq(4, 5, 6, 7, 8, 9) 
   //List(1, 2, 3) 
   num1.diff(num2) 
   //List(4, 5, 6) 
   num1.intersect(num2) 
   //List(1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9) 
   num1.union(num2) 


The examples are self-explanatory. But what about the union function? It keeps duplicates. What if we want to get rid of them? For this purpose, use the distinct function:

//List(1, 2, 3, 4, 5, 6, 7, 8, 9) 
num1.union(num2).distinct 


Here is an illustration of the functions above:

Scala collection Euler functions

#5 map List Elements

Probably map is the most widely used function in Scala collections. Its power is better to show off than talk about it:

val numbers = Seq(1,2,3,4,5,6) 
   //List(2, 4, 6, 8, 10, 12) 
   numbers.map(n => n * 2) 
   val chars = Seq('a', 'b', 'c', 'd') 
   //List(A, B, C, D) 
   chars.map(ch => ch.toUpper) 


The logic of the map function is that you iterate through each element of a collection and apply a function to the elements. You can even leave elements as they are, without applying any function, but in this case, the map function is absolutely useless because you will get the same collection after mapping.

#6 flatMap

I still remember how was difficult for me to understand where and how to apply the flatMap function. In general, this is caused by wide variety of situations where flatMap can be helpful. The first thing I recommend is for every beginner to look at the name of the function more attentively. You should notice that flatMap consists of two functions that we’ve already considered above:

map & flatten

Let’s assume that we want to see how uppercase and lowercase characters look in the alphabet.

 val abcd = Seq('a', 'b', 'c', 'd') 
   //List(A, a, B, b, C, c, D, d) 
   abcd.flatMap(ch => List(ch.toUpper, ch)) 


Since in this article I talk only about collection functions, I’ll omit examples with Futures and Options.

#7 Check the Entire Collection for a Condition

There is a well-known scenario when you need to ensure that all elements in a collection meet some requirement. If at least one of the elements doesn’t correspond to the condition, you need to do something.

 val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2) 
   //ture numbers.forall(n => n < 10) 
   //false numbers.forall(n => n > 5) 


The function forall is created for this sort of task.

#8 Partitioning of a Collection

What if you have a plan to separate a collection into two new collections by some rule? This can be done with help of the partition function. So let’s put all even numbers in one collection and all odd numbers in another:

val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2) 
   //(List(2, 6, 4, 2), List(3, 7, 9, 5, 1)) 
   numbers.partition(n => n % 2 == 0) 


#9 Fold?

Another one popular operation is fold. In the context of Scala, you can usually think about foldLeft and foldRight. In general, they do the same job but from the different sides: 

val numbers = Seq(1, 2, 3, 4, 5) 
//15 numbers.foldLeft(0)((res, n) => res + n) 


The code sample above needs some explanation. In the first pair of parentheses, we put a start value. In the second pair of parentheses, we define the operation that needs to be performed for each element of the numbers sequence. On the first step, n = 0, then it evolves according to the sequence elements.

Just to clarify, I want to provide another example of foldLeft. Let’s count the number of characters in a sequence of words:

val words = Seq("apple", "dog", "table") 
   //13 words.foldLeft(0)((resultLength, word) => resultLength + word.length) 


#10 Your Favorite Function

After a so long enumeration, it would be cool to see your favorite function from Scala collections. Write about it in the comments and provide an example of its usage.

Cooperation Among Functions

As I promised in the beginning of this post, I'll provide an example of function composition. Recently, I was passing a Codility test and there was a task:

Given string S, you have to find the longest substring that contains uppercase and lowercase characters, but not numbers.

Example: dP4knqw1QAp
Answer: QAp

So how do we solve this task with help of Scala collection functions?

def theLongest(s: String): String = { 
   s.split("[0-9]") 
     .filter(str => str.exists(ch => ch.isUpper)) 
     .maxBy(str => str.length) } 


This function solves the problem. If the input string doesn’t contain any suitable substring, then UnsupportedOperationException will be thrown.

Summary

Scala has an incredibly powerful collection API. You can do a lot of stuff with it. Furthermore, the same things can be done in different ways, e.g. look at the section about Euler functions. The API is rich and its study requires time and practicing.

Tutorial: WordPress as distributed microservices on Kubernetes.

Topics:
scala ,functional programming ,java ,collection functions ,tutorial

Published at DZone with permission of Alexey Zvolinskiy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

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

X

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

{{ parent.tldr }}

{{ parent.urlSource.name }}