📜 ⬆️ ⬇️

Scala WAT: Collections

Last time we dealt with the processing of optional values, it turned out that using the elegant means of the Scala library incorrectly, we can continue to shoot our legs.

This time we will move on to the collections. The standard library for collections in Scala is so rich that it can offer ready-made methods for even the most demanding developers. In what cases to use what methods are usually not described and everything is learned through experience. Usually, at the beginning everyone will recognize filter and map , this can be the limit, because with a certain imagination one can implement a lot of algorithms only on these functions. However, these methods may not be optimal or produce results that are impossible for the domain, which, however, will have to be processed.

Below we will discuss which functions of the standard library are often used incorrectly and what can be improved.

foreach and for (val i = 0; i <n; i ++)


When switching to Scala, many people experience a breakdown due to the lack of for(;;) . Someone, especially those who wrote in C, thinks that without such a cycle you cannot write programs at all, the more advanced ones try to write analogs for while with the removal of the initial conditions and the cycle step into external code, for example:
')
 var i = 0 //  var! while(i < n) { //  - ,   i i = i+1 } 

In fact, the most accurate analogue of for(val i = 0; i< n; i++) is for(i <- 0 until n) ,
so everything here was on the surface, although on the move it is not always visible. To write correctly you need to know the work of the Range class and see examples of its use on blogs, such as Code Commit .

Iterator


Often, when working with old Java code, there are classes that can not be iterated. As an example, take java.sql.ResultSet ( Enumeration also rolls). It is not Iterable, that is, there is no transparent conversion to JavaConversions , and you have to work with it only in imperative form or copy it into the contents into an intermediate mutable collection, alternatively, build immutable through the builder. Fearfully.

For this case, the standard Scala library has an Iterator class, which allows you to make an edible Iterator from a ResultSet , which is at least Traversable :

 val resultSetIterator = Iterator.continually(resultSet).takeWhile(_.next()) 

Simple replacements and binary logic


We start with simple substitution rules, when a chain of calls can be replaced by a simpler one or even one simple method. The simplest methods that can help you are exists , exists , forall and find . I often watched:

 option.map(myValueIsGoodEnough).getOrElse(false) 

instead of
 option.exists(goodEnoughValue) //   `option exists goodEnoughValue` 

then
 iterable.filter(goodEnough).headOption 

instead of
 iterable.find(goodEnough) 

even it was like this (admittedly, right in our code!)
 iterable.foldLeft(true)(_ && goodEnough) 

instead
 iterable.forall(goodEnough) 

Needless to say, simpler options are not only simpler for perception, but also implemented more efficiently, due to the fact that map , filter and foldLeft will check the entire collection, no matter how long it is, while exists , find and forall will end as soon as they find a suitable (or inappropriate) element and will not generate an additional intermediate collection.

There were also several useful features on the Scala course on Coursera.com : span , dropWhile and takeWhile . Using them may also not be obvious in practice, because the filter works successfully for these cases, too, really less efficiently, because it does not know that, at some point, it is no longer necessary to check the elements: they all fit or don’t fit. For example, I myself until recently, removed the beginning and end of a sequence of exchange rates that are not included in the interval, through filter , and not through dropWhile and takeWhile .

Aggregates


The methods fold , foldLeft and foldRight very powerful and they can be used to solve completely different tasks.
Let's stop, for example, on foldLeft , with its help you can get the sum of the elements of the collection:

 iterable.foldLeft(0) { (accum, elem) => accum + elem } 

The canonical spelling for this code is:

 iterable.foldLeft(0) { _ + _ } 

Martin Odersky for this showed an interesting version on Scala Days:

 (0 /: iterable)(_ + _) 

says, as if dominoes are falling from left to right :) More pluses are described here , but I’m still skeptical about symbol operators, if they are not well-known for the domain.

In any case, in this situation you should not write this code, because there is a special method for a collection with elements from the Typeclass Numeric , you can write more simply:

 iterable.sum 

The min and max functions are also available (special craftsmen like to sort the collection and take the head / tail, well, we haven't seen anything like this).

Methods for folding are better reserved for applying one after the other steps of the high-level algorithm, for example, in chain-of-responsibility, or make reduce in your map-reduce.

Sometimes, when processing graphs and, in general, information distributed in time, you have to process elements in pairs (current and previous), in this case you might really want, I wanted to use for(;;) and play with indices,

 for(i <- 1 until seq.size) { result ++= combine(seq(i-1), seq(i)) } 

in Scala, you can sew a sequence with itself, shifted by one element and then use the function that processes both elements:

 seq.zip(seq.drop(1)).map(combine) //    list.zip(list.tail).map(combine) // ,     

Just remember to check that the sheet is not empty!

The same code is more correct to write as

 seq.sliding(2).map(calculateDelta) 


And now the good news, JavaOne turned out to portray many of these simplifications to the guys from IntelliJ , and by the Scala Days they managed to implement them and many more



The guys now have a special person engaged in Scala inspections, so if you have some interesting thoughts on simplification - create tickets , everything will be there!

Write a good code and be happy.

Source: https://habr.com/ru/post/184310/


All Articles