Scala vals vs vars

I am new to Scala, but I like to know what is the preferred way to solve this problem. Let's say I have a list of items, and I want to know the total amount of items that are checked. I could do something like this:

val total = items.filter(_.itemType == CHECK).map(._amount).sum 

This will give me what I need, the sum of all checks in an immutable variable. But he does it with three iterations. To filter the checks, you again need to match the amounts, and then the amount. Another way is to do something like:

 var total = new BigDecimal(0) for ( item <- items if item.itemType == CHECK ) total += item.amount 

This gives me the same result, but with 1 iteration and a mutable variable, which seems fine too. But if I wanted to extract additional information, say that the total number of checks will require more counters or mutable variables, but I no longer have to iterate over the list. Not like a “functional” way to achieve what I need.

 var numOfChecks = 0 var total = new BigDecimal(0) items.foreach { item => if (item.itemType == CHECK) { numOfChecks += 1 total += item.amount } } 

So, if you need to have a bunch of counters or totals in the list, it’s preferable to save mutable variables or not to worry about it, something like:

 val checks = items.filter(_.itemType == CHECK) val total = checks.map(_.amount).sum return (checks.size, total) 

which seems more readable and uses only vals

+4
source share
3 answers

You can use foldLeft for this:

 (0 /: items) ((total, item) => if(item.itemType == CHECK) total + item.amount else total ) 

The following code will return a tuple (number of checks → sum of sums):

 ((0, 0) /: items) ((total, item) => if(item.itemType == CHECK) (total._1 + 1, total._2 + item.amount) else total ) 
+6
source

Another way to solve your problem in one iteration is to use views or iterators:

 items.iterator.filter(_.itemType == CHECK).map(._amount).sum 

or

 items.view.filter(_.itemType == CHECK).map(._amount).sum 

Thus, the evaluation of the expression is delayed until sum called.

If your objects are case classes, you can also write it like this:

 items.iterator collect { case Item(amount, CHECK) => amount } sum 
+8
source

I think that talking about doing “three iterations” is a bit misleading. In the end, each iteration does less work than a single iteration with everything. Therefore, it does not automatically follow that repeating three times will take longer than repeating.

Creating temporary objects, now this is troubling because you will beat the memory (even with caching), which is not the case with a single iteration. In such cases, view will help, even if it adds more method calls to do the same job. Hope the JVM optimizes this. See Moritz answer for more information on views.

+7
source

All Articles