How to write this function efficiently? - scala

Suppose I am writing function foo: Seq[B] => Boolean like this:
case class B(xs: Seq[Int])
def foo(bs: Seq[B]): Boolean = bs.map(_.xs.size).sum > 0
The implementation above is suboptimal (since it's not necessary to loop over all bs elements to return true). How would you implement foo efficiently ?

Well, for 0 this is kind of trivial:
bs.exists(!_.xs.isEmpty)
does the job, because as soon as you find a non-empty xs, you are done.
Now, suppose that the threshold is not trivial, e.g. 42 instead of 0.
You can then take the iterator of bs, incrementally aggregate the values using scanLeft, and then check whether there exists an intermediate result that is greater than zero:
def foo(bs: Seq[Int]): Boolean = bs
.iterator
.scanLeft(0)(_ + _.xs.size)
.exists(_ > 42)

Related

Fold method using List as accumulator

To find prime factors of a number I was using this piece of code :
def primeFactors(num: Long): List[Long] = {
val exists = (2L to math.sqrt(num).toLong).find(num % _ == 0)
exists match {
case Some(d) => d :: primeFactors(num/d)
case None => List(num)
}
}
but this I found a cool and more functional approach to solve this using this code:
def factors(n: Long): List[Long] = (2 to math.sqrt(n).toInt)
.find(n % _ == 0).fold(List(n)) ( i => i.toLong :: factors(n / i))
Earlier I was using foldLeft or fold simply to get sum of a list or other simple calculations, but here I can't seem to understand how fold is working and how this is breaking out of the recursive function.Can somebody plz explain how fold functionality is working here.
Option's fold
If you look at the signature of Option's fold function, it takes two parameters:
def fold[B](ifEmpty: => B)(f: A => B): B
What it does is, it applies f on the value of Option if it is not empty. If Option is empty, it simply returns output of ifEmpty (this is termination condition for recursion).
So in your case, i => i.toLong :: factors(n / i) represents f which will be evaluated if Option is not empty. While List(n) is termination condition.
fold used for collection / iterators
The other fold that you are taking about for getting sum of collection, comes from TraversableOnce and it has signature like:
def foldLeft[B](z: B)(op: (B, A) => B): B
Here, z is starting value (suppose incase of sum it's 0) and op is associative binary operator which is applied on z and each value of collection from left to right.
So both folds differ in their implementation.

Correct way to work with two instances of Option together

When I have one Option[T] instance it is quite easy to perform any operation on T using monadic operations such as map() and flatMap(). This way I don't have to do checks to see whether it is defined or empty, and chain operations together to ultimately get an Option[R] for the result R.
My difficulty is whether there is a similar elegant way to perform functions on two Option[T] instances.
Lets take a simple example where I have two vals, x and y of type Option[Int]. And I want to get the maximum of them if they are both defined, or the one that is defined if only one is defined, and None if none are defined.
How would one write this elegantly without involving lots of isDefined checks inside the map() of the first Option?
You can use something like this:
def optMax(op1:Option[Int], op2: Option[Int]) = op1 ++ op2 match {
case Nil => None
case list => list.max
}
Or one much better:
def f(vars: Option[Int]*) = (for( vs <- vars) yield vs).max
#jwvh,thanks for a good improvement:
def f(vars: Option[Int]*) = vars.max
Usually, you'll want to do something if both values are defined.
In that case, you could use a for-comprehension:
val aOpt: Option[Int] = getIntOpt
val bOpt: Option[Int] = getIntOpt
val maxOpt: Option[Int] =
for {
a <- aOpt
b <- bOpt
} yield max(a, b)
Now, the problem you described is not as common. You want to do something if both values are defined, but you also want to retrieve the value of an option if only one of them is defined.
I would just use the for-comprehension above, and then chain two calls to orElse to provide alternative values if maxOpt turns out to be None.
maxOpt orElse aOpt orElse bOpt
orElse's signature:
def orElse[B >: A](alternative: ⇒ Option[B]): Option[B]
Here's another fwiw:
import scala.util.Try
def maxOpt (a:Option[Int]*)= Try(a.flatten.max).toOption
It works with n arguments (including zero arguments).
Pattern matching would allow something easy to grasp, but that might not be the most elegant way:
def maxOpt[T](optA: Option[T], optB: Option[T])(implicit f: (T, T) => T): Option[T] = (optA, optB) match {
case (Some(a), Some(b)) => Some(f(a, b))
case (None, Some(b)) => Some(b)
case (Some(a), None) => Some(a)
case (None, None) => None
}
You end up with something like:
scala> maxOpt(Some(1), None)(Math.max)
res2: Option[Int] = Some(1)
Once you have that building, block, you can use it inside for-comp or monadic operations.
To get maxOpt, you can also use an applicative, which using Scalaz would look like (aOpt |#| bOpt) { max(_, _) } & then chain orElses as #dcastro suggested.
I assume you expect Some[Int]|None as a result, not Int|None (otherwise return type has to be Any):
def maxOption(opts: Option[Int]*) = {
val flattened = opts.flatten
flattened.headOption.map { _ => flattened.max }
}
Actually, Scala already gives you this ability more or less directly.
scala> import Ordering.Implicits._
import Ordering.Implicits._
scala> val (a,b,n:Option[Int]) = (Option(4), Option(9), None)
a: Option[Int] = Some(4)
b: Option[Int] = Some(9)
n: Option[Int] = None
scala> a max b
res60: Option[Int] = Some(9)
scala> a max n
res61: Option[Int] = Some(4)
scala> n max b
res62: Option[Int] = Some(9)
scala> n max n
res63: Option[Int] = None
A Haskell-ish take on this question is to observe that the following operations:
max, min :: Ord a => a -> a -> a
max a b = if a < b then b else a
min a b = if a < b then a else b
...are associative:
max a (max b c) == max (max a b) c
min a (min b c) == min (min a b) c
As such, any type Ord a => a together with either of these operations is a semigroup, a concept for which reusable abstractions can be built.
And you're dealing with Maybe (Haskell for "option"), which adds a generic "neutral" element to the base a type (you want max Nothing x == x to hold as a law). This takes you into monoids, which are a subtype of semigroups.
The Haskell semigroups library provides a Semigroup type class and two wrapper types, Max and Min, that generically implement the corresponding behaviors.
Since we're dealing with Maybe, in terms of that library the type that captures the semantics you want is Option (Max a)—a monoid that has the same binary operation as the Max semigroup, and uses Nothing as the identity element. So then the function simply becomes:
maxOpt :: Ord a => Option (Max a) -> Option (Max a) -> Option (Max a)
maxOpt a b = a <> b
...which since it's just the <> operator for Option (Max a) is not worth writing. You also gain all the other utility functions and classes that work on Semigroup and Monoid, so for example to find the maximum element of a [Option (Max a)] you'd just use the mconcat function.
The scalaz library comes with a Semigroup and a Monoid trait, as well as Max, Min, MaxVal and MinVal tags that implement those traits, so in fact the stuff that I've demonstrated here in Haskell exists in scalaz as well.

How to get a set of elements in a list based on element index in Scala?

I have one list and another list contains the index I am interested in. e.g
val a=List("a","b","c","d")
val b=List(2,3)
Then I need to return a list whose value is List("b","c"), since List(2,3) said I like to take the 2nd and 3rd element from element "a". How to do that?
val results = b.map(i => a(i - 1))
I like the order of my expressions in the code to reflect the order of evaluation, so I like using the scalaz pipe operator to do this kind of thing |>
b.map(_ - 1 |> a)
It's especially natural when one is used to writing bash scripts.
Consider this apply method which checks (avoids) possible IndexOutOfBoundsException,
implicit class FetchList[A](val in: List[A]) extends AnyVal {
def apply (idx: List[Int]) = for (i <- idx if i < in.size) yield in(i-1)
}
Thus
a(b)
res: List[String] = List(b, c)

Initial value in loops

Suppose you are writing a tail-recursive loop function to evaluate a collection of elements according to some criterium and want to end up with the element that scores best, and its score.
Naturally you will pass the best scoring element so far, as well as its score, as parameters to the function.
But since there is no best element at the start of the recursion, what should you initially pass as parameters to the loop function? Not wanting to use null, you could use Option[T] as parameter types, but then you have to check for isEmpty at each recursion while you know that it always has a value after the initial call. Isn't there a better way?
You can use list.head as initial value and loop over list. The first evaluation will be "wasted" since you're evaluating list.head against itself but that will calculate the score for list.head and the rest of the iteration can carry on and do what you want.
How is a "best element" evaluated?
Typically that is done through a numeric value.
At the start, you typically set that value to a number. Best practices state that the number should be defined as a constant, something like the name of MIN_VALUE. That value could be zero, negative, or the minimum floating point number that is representable.
The head of the list, as #vptheron answered, seems to be the best as you don't have a good starting value.
But, rather than use a tail-recursive function...
def getBestScore(scores: List[A]): A = {
def go(as: List[A], acc: A): A = as match {
case x :: xs => go(xs, getBest(acc, x)) // getBest: ((A, A) => A)
case Nil => acc
}
go(scores, scores.head)
}
... you can use foldLeft to make it concise.
val best = scores.foldLeft(scores.head)(getBest)
Example:
scala> def getBest(x: Int, y: Int) = if(x > y) x else y
getBest: (x: Int, y: Int)Int
scala> val scores = List(1, 20, 3)
scores: List[Int] = List(1, 20, 3)
scala> scores.foldLeft(scores.head)(getBest)
res6: Int = 20

A function to determine whether one number is a factor of another in an argument to foldLeft in Scala

I am trying to define a function in Scala to determine whether a number is prime as follows:
def isPrime(n: Int): Boolean = {
if (n == 2) true
else {
List(3 to math.sqrt(n)).foldLeft(isFactor(),0)
}
def isFactor(x:Int, n:Int):Boolean=(n%x)==0
}
What arguments to give to the foldLeft call, given that I have already defined isFactor?
I guess you want to find if any of the items in the list is a factor of n. So for an empty list you should then start with false, since an empty list holds no factors of n. However, you'll have to keep comparing the collected result with the isFactor result. The simplest of course with be to check out the list.exists(...)-method.
thanks to advice from #thoredge, I've been able to do this using exists() as follows:
def isPrime(n: Int): Boolean = n match {
case 2 => true
case _ => !(2 to math.sqrt(n).ceil.toInt).exists((x) => n % x == 0)
}